لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 02/15/24 في كل الموقع
-
السلام عليكم ده مسائل من موقع codwars Create a function that always returns True/true for every item in a given list. However, if an element is the word 'flick', switch to always returning the opposite boolean value. وده الحل بناعي , بس بيضهر خطاء علي الموقع codewars boo = 'True' for row in range(len(arr)): if 'flick' in arr[row]: boo = 'False' arr[row] = boo else: arr[row] = boo print(arr)3 نقاط
-
اظهار القط اظهار الخلفية اظهار الجبن اظهار المتاهة حلقة : اذا ضغطت على السهم اليمين يتحرك القط يميناَ و اذا ضغطت على السهم الايسر يتحرك القط يساراَ و اذا ضغطت على السهم العلوي يتحرك القط للاعلى و اذا ضغطت على السهم السفلي يتحرك القط للاسفل و إلا يتوقف القط عن الحركة. حلقة : إذا ضغطت على السهم الأيمن وإرتطم القط بجدار المتاهة فا إعرض س = - 2 واظهر صوت القط إذا ضغطت على السهم الأيسر وإرتطم القط بجدار المتاهة فا إعرض س = + 2 واظهر صوت القط إذا ضغطت على السهم العلوي وإرتطم القط بجدار المتاهة فا إعرض ص = - 2 واظهر صوت القط إذا ضغطت على السهم السفلي وإرتطم القط بجدار المتاهة فا إعرض ص = + 2 واظهر صوت القط اذا وصل القط لقطعة الخبز فا أحضر صوت فرحٍ اظهر رسالة تقول لقد ربحت ما رأيك ؟2 نقاط
-
النوع radio هو لتحديد عنصر واحد ولكن عندما استخدمه يتم تحديد اكثر من عنصر لماذا وهل ال table و tr نفس الشيء لانهم يعطون نفس النتيجة هذا هو الكود <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <h1>فورم تسجيل</h1> <form> <table> <tr> <td> <label for="usernamr">usernamr</label> </td> <td><input type="text" id="username" /><br /></td> </tr> <tr> <td> <label for="pwd">passwoord</label> </td> <td><input type="password" id="pwd" name="pwd" /><br /></td> </tr> <td> <label>Reistar palan</label> </td> <td> <div> <input type="radio" id="starter" name="plan" value="starter" /> <label for="starter">starter</label> </div> <div> <input type="radio" id="business" name="palan" value="business" /> <label for="business">Business</label> </div> <div> <input type="radio" id="premium" name="palan" value="premium" /> <label for="premium">premium</label> </div> </td> </table> <table> <label for="description">description</label> </table> <table> <textarea name="description" id="description" cols="30" rows="10"></textarea> </table> <table> <label for="agree">Agree</label> </table> <table> <input type="checkbox" id="agree" name="agree" /> <label for="agree">I agree to terms and conditions</label> </table> <table> <input type="submit" value="Reistar" /> </table> <td><input type="button" value="clear" /></td> </form> </body> </html>2 نقاط
-
شكرااا جدا والله علي المعلوما ده شكرااا اوي تمام , شكراا جدا لحصرتك انا بكتب الكود ده فا بيظهر خظاء علي الموقع مش عارف ليه مغ ان الكود صح def flick_switch(lst): boo = 'True' for i in range(len(lst)): if lst[i] == 'flick': boo = not boo lst[i] = boo else: lst[i] = boo return lst arr = ['codewars' , 'flick' , 'code' , 'wars'] print(flick_switch(arr))2 نقاط
-
2 نقاط
-
#include <iostream> using namespace std; int minpositive(int nums[], int size){ int check = 50; for(int i = 0; i < size; i++){ if(nums[i] > 0 && check > nums[i]){ check = nums[i]; } } //return check; } int main(){ int numbers[] = { -10, -20, 15, 100, 10, 5, -50, 0 }; // 5 int numssize = sizeof(numbers) / sizeof(numbers[0]); cout << minpositive(numbers, numssize) << "\n"; return 0; } لما بعمل كومنت لل return بيطلع رقم 8 اللي هو عدد العناصر في ال array ممكن اعرف العملية دي تمت ازاي؟ ولو نفس ال function بس انا مش عارف الارقام ازاي اجيب اصغر واحد بطريقة dynamic؟2 نقاط
-
أحاول فهم آلية عمل Sequelize من خلال مثال بسيط: حيث يمكن أن يكون لدى المستخدم العديد من المنشورات، ويمكن أن يكون للمنشور مستخدم واحد فقط. أولاً، لا أعرف ما إذا كان يجب علي استخدام عمليات الترحيل (Migrations) أو النماذج (Models) مع المزامنة (Sync) لإنشاء قاعدة البيانات الخاصة بي، إذ يبدو أنني أحتاج إلى كتابة نفس الكود تقريبًا في كليهما. وذلك هو رمز الترحيل لجدول المستخدمين: module.exports = { up: (queryInterface, Sequelize) => { return queryInterface.createTable('Users', { id: { allowNull: false, autoIncrement: true, primaryKey: true, type: Sequelize.INTEGER }, username: { allowNull: false, type: Sequelize.STRING, unique: true }, password: { allowNull: false, type: Sequelize.STRING }, email: { allowNull: false, type: Sequelize.STRING, unique: true }, createdAt: { allowNull: false, type: Sequelize.DATE }, updatedAt: { allowNull: false, type: Sequelize.DATE } }); }, down: (queryInterface, Sequelize) => { return queryInterface.dropTable('Users'); } }; وهذا هو نموذج المنشور: 'use strict'; module.exports = (sequelize, DataTypes) => { const User = sequelize.define('User', { username: DataTypes.STRING, password: DataTypes.STRING, email: DataTypes.STRING }, { classMethods: { associate: (models) => { User.hasMany(models.Post); } } }); return User; }; هل يجب علي أيضًا تحديد أن اسم المستخدم والبريد الإلكتروني لا يمكن أن يكونا فارغين ويجب أن يكونا فريدين هنا في النموذج؟ وكيف يمكنني إضافة المفتاح الخارجي؟ في أحد البرامج التعليمية، قيل لي أن قاعدة البيانات تضيف المفتاح الخارجي تلقائيًا، لكنني لا أعتقد أنه يعمل إذا استخدمت عمليات الترحيل، يجب أن أقوم بتعيينه يدويًا، أليس كذلك؟1 نقطة
-
#include <iostream> using namespace std; int main() { int numbers[] = { 10, 20, 3, 30, 5, 7, 40 }; int numssize = size(numbers); cout << numssize; return 0; } بتجيبلي 'size' was not declared in this scope1 نقطة
-
مرحباً يا عائلة اكاديمية حاسوب. كنت ارجو منكم بتبديل دورتي جافاسكربت بدورة php، وذلك بسبب انني اجد ان اغلب محتوايات الدورة فيها صعوبة نوعاً ما. انا مشترك في دورة جافا سكربت من اشهر ولكن لم استكمل دراستي وكنت قد تود بإستبدالها بدورة php. هل هذا ممكن ؟ من فضلكم طبعً وكامل جزيل الشكر لكل اساتذة حسوب بالطبع.1 نقطة
-
ارسلت لهم رسالة عبر الشات ارجوا ان يقومو بالرد. كما اريد ان اشكرك استاذ عدنان على كل الدعم والمساعدة التي كنت تقوم بها طول هذا الفترة. تحياتي1 نقطة
-
1 نقطة
-
السلام عليكم ورحمة الله وبركاته لدي مشكلة في تطبيق الانميشن عند الفلترة في ال grid layout حيث ان الانميشن لا تطبق من اول مرة او بالأحرى عندما يكون كل العناصر موجودة و اريد فلترتها ، لا تطبق الانميشن الا عند الضغط على فلتر او زر ثانٍ ، هذا ديمو المشروع الذي اعمل عليه ،https://creative-lollipop-f36a4c.netlify.app/ لم اعرف المشكلة و عانيت جدا في حلها في المرفق تجد ملف المشروع و ايضا فيديو توضيحي للمشكلةو بارك الله فيكم Abraj - Media Center - Google Chrome 2024-02-15 10-50-17.mp4 Abraj-deployed.zip1 نقطة
-
1 نقطة
-
هل هناك فرق بين المبرمج والمطور؟ ما هو؟ أرجو شرحا مفصلا عنهما1 نقطة
-
1 نقطة
-
هناك خطأين لديك فى الكود . اولا فى ملف ال script.js حين تغير ال layout الى ال flex يجب ان يتم استدعاء AOS.refresh() حيث ان ال flex يكون غير مرئى فى بداية تحميل الصفحة ولذلك لا يتم تحميل ال animation حيث يجب ان يكون ظاهر فى الصفحة حتى يعمل جيدا . ثانيا فى ملف ال style.css انت تضع ال opacity ب 0 فى ال flex layout للصور لذلك ال animation لا يعمل جيدا يجب ان تحذف ال opacity وتجعلها فقط ب 0 اذا لم يكن قد حدث اى animation . فى سطر 83 فى ملف ال Script.js قم بتبديل الدالة بهذا الكود //add active class to the layout style const layouts=document.querySelectorAll('.layout span') layouts.forEach(layout=>{ layout.addEventListener('click',function(){ if (this.classList.contains('active')) { return; } const dataLayout=this.dataset.layout; //add active for layout btns layouts.forEach(layout =>{ layout.classList.remove('active'); }) layout.classList.add('active'); // Hide all layout containers const layoutContainers = document.querySelectorAll('.masonry-gallery'); layoutContainers.forEach(container => { container.classList.remove('active'); }); //Remove the animation class from the images,videos (media) mediaElements.forEach(function (media) { media.classList.remove('fade-in-up'); }) // Show the layout container with the corresponding layout attribute const activeContainer = document.querySelector(`.masonry-gallery[data-layout="${dataLayout}"]`); activeContainer.classList.add('active'); //Get the images, vidoes of the active layout const images = activeContainer.querySelectorAll('.masonry-image'); images.forEach(function(img){ // img.classList.add('fade-in-up'); // setTimeout(function(){ // img.classList.remove('fade-in-up'); // // img.classList.add('show') // },1000) }) if(activeContainer.classList.contains('grid')){ masonry.layout(); } else{ AOS.refresh(); } }) }) وفى ملف ال style.css سطر 426 قم بتبديله بهذا الكود .gallery-items .flex.masonry-gallery .masonry-image{ /* width: 18rem; */ width: 100%; height: 25rem; margin-right: 0.85rem; /* transition: all 0.3s ease-out; */ /* animation: fadeInUp 1s ease-out forwards ; */ } .gallery-items .flex.masonry-gallery .masonry-image:not(.aos-animate) { opacity: 0; } وقد قمت برفع الملفات لتستخدمها اذا اردت. ولكنك ستجد مشكلة اخرى وهى انه يحدث delay فى ال animation وهذا سببه عدة اخطاء فى الكود من ال style و ال js ولكن حاليا ال animation تعمل جيدا. واذا كان هناك اى شئ اخر فلتخبرنى script.js style.css1 نقطة
-
1 نقطة
-
المشكلة تحدث عند الإنتقال من زر all إلى photos وأيضًا videos، لكن لا تحدث عند الإنتقال من videos إلى photos أو العكس، لذا تفقد ما الخطأ في المنطق الخاص بذلك، ربما هناك كلاس لا يتم حذفه أو ما شابه.1 نقطة
-
لا مشكلة لديك، قمت بإختبار المشروع سواء بشكل محلي أو رابط netlify لا يوجد مشكلة تفقد الفيديو: ربما المشكلة لديك هي في الكاش (الملفات المؤقتة) حاول إعادة تحديث الصفحة بالضغط على CTRL + F5 أيضًا حاول تحديث المتصفح. 2024-02-15_11-03-22.mp41 نقطة
-
لقد قمت بحل هذه السؤال من قبل علي الموقع و المساله بتطلب منك كتابة دالة تعيد القيمة True لكل عنصر في قائمة معينة. ولكن، لو كان أحد العناصر هو الكلمة "flick"، فستقوم الدالة باعادة القيمة المعاكسة (False) . من المفترض الحل يكون بهذه الطريقه def always_true(xs): flick_seen = False for row in range(len(xs)): if xs[row] == "flick": flick_seen = True if flick_seen: xs[row] = "False" else: xs[row] = "True" return xs # اختبار الدالة arr = ["a", "b", "c", "flick", "d", "e"] print(always_true(arr))1 نقطة
-
إذا كان التعبير صحيحًا، فإن Not تجعله خاطئًا. إذا كان التعبير خاطئًا، فإن Not تجعله صحيحًا. أي عكس القيمة المنطقية لتعبيرات Boolean.1 نقطة
-
نعم بالفعل كلمة not تقوم بتبديل القيمة الحالية من True الى False والعكس1 نقطة
-
ان السؤال المطلوب انه اذا كان العنصر يساوى flick فيجب ان تغير القيمة الحالة التى تقوم بارجاعها . يخبرك انه فى بداية البرنامج يجب ان تقوم بارجاع true واذا ظهرت كلمة flick يجب ان تبدل true ب false اذا ظهرت كلمة flick مرة اخرى يجب انت تبدل false ب true مرة اخرى . ما تقوم به انت هو انك تبدل true ب false مرة واحدة فقط واذا ظهرت كلمة flick مرة ثانية لا تقوم بتبديل false ب true boo = True for row in range(len(arr)): if 'flick' in arr[row]: boo = not boo arr[row] = boo else: arr[row] = boo print(arr) لذلك نقوم باستخدام هذا السطر boo = not boo وهذا السطر يقوم بتبديل قيمة boo الحالية فان كانت boo تساوى True سيقوم بتبديلها ب False و العكس اذا كانت ب False فسيقوم بتبديلها ب True1 نقطة
-
المطلوب منك هو كتابة دالة تُرجع دائمًا True لأي عنصر في قائمة معينة، ولديك العنصر هو كلمة "flick"، أي يجب على الدالة تبديل السلوك لترجع دائمًا القيمة المنطقية المعاكسة. ولديك مشكلتان: 1- التكرار اللانهائي، حيث عندما تواجه حلقة for عنصرًا "flick" ، يتم تعيين boo إلى "False"، ثم يتم تعيين العنصر نفسه إلى boo. لكن بما أن boo الآن "False" ، فسيتم إعادة تعيين boo إلى "True" في التكرار التالي، سيستمر هذا التناوب إلى أجل غير مسمى ، مما يؤدي إلى حلقة لانهائية. 2- عدم معالجة عناصر غير السلسلة، افترض الكود أن جميع العناصر في القائمة هي سلاسل، فإذا واجهت عنصرًا غير سلسلة (مثل رقم أو قائمة فرعية) ، فسيتسبب ذلك في حدوث خطأ TypeError. لذا سيصبح الكود كالتالي وأضفت تعليقات لتفهم ما يحدث: def always_true(arr): """ تعديل القائمة المعطاة `arr` لترجع دائمًا True عند فحصها لمعرفة صحتها. إذا كان عنصر في `arr` هو كلمة "flick" ، فإن الدالة تقلب السلوك لترجع دائمًا القيمة المنطقية المعاكسة. ومع ذلك ، لا تعدل القائمة الأصلية مباشرة لتجنب التأثيرات الجانبية المحتملة. Args: arr: القائمة التي تريد تعديلها. Returns: None. تعدل الدالة القائمة المُدخلة مباشرة. Raises: TypeError: إذا لم يكن عنصر في `arr` سلسلة. """ truth_state = True for i in range(len(arr)): if arr[i] == 'flick': truth_state = not truth_state # تبديل حالة الصدق arr[i] = 'flicked' # تمييز العنصر لتجنب التكرار اللانهائي arr[i] = truth_state return None # غير ضروري ، لكن يمكن الاحتفاظ به للتناسق # مثال على الاستخدام arr = ['a', 'b', 'flick', 'c', 'flick', 'd'] always_true(arr) print(arr) # إخراج: ['True', 'True', 'flicked', 'True', 'flicked', 'True'] # مثال آخر arr2 = [0, 1, 'flick', True, False] always_true(arr2) print(arr2) # إخراج: [True, True, 'flicked', True, False]1 نقطة
-
1 نقطة
-
1 نقطة
-
هل اقدر اعدل على ملفات الترحيل اللي تم إنشاؤها من قبل لارافيل, مثلا جدول users الذي يتم انشاؤه من قبل لارافيل ابغى اغير اسمه الى students وكمان ابغى احذف اعمدة فيه واعدل عليه .. هل اقدر اعدل بدون ماتواجهني مشاكل ؟1 نقطة
-
بالاضافة للحل السابق اذا قمت بتغير اسم الجدول و قمت بتبديل اسم العمود الخاص بالايميل او الباسورد فسيقابلك مشكلتان. اولا اذا قمت بتغير اسم الجدول فيجب ان تنشأ model جديد ليمثل الجدول الجديد . يمكنك انشاء ال model عن طريق هذا الامر , لنفرض ان الجدول الجديد يسمى students . php artisan make:model Student او يمكنك استخدام الملف الخاص بلارافيل User اذا لم تكن تريد ان تنشأ ملف جديد . ويمكنك كتابة هذا السطر فى الملف وسيتعامل ملف ال User مع الجدول الجديد protected $table = 'students'; اذا كنت تستخدم laravel Authentication وقمت بتغير الحقل email فسيجب ان تقوم بتغيرات فى دوال ال login و ال register ليستخدمو الحقل الجديد1 نقطة
-
اولا اذا قمت بعمل comment لسطر ال return فى الدالة minpositive فان الكود لن يعمل وسيظهر لك خطأ لانك قد قمت بتعريف الدالة minpositive انها تقوم بارجاع رقم int و فى داخل الدالة لا تقوم بارجاع اى قيمة لذا سيظهر لك خطأ . ثانيا لتقوم بارجاع القيمة بطريقة dynamic لتقم باستخدام هذا الكود int minpositive(int nums[], int size) { int check = nums[0]; for (int i = 0; i < size; i++) { if (nums[i] > 0 && abs(check) > nums[i]) { check = nums[i]; } } if (check < 0) return 0; return check; } اولا نقم بتعريف المتغير check باول قيمة فى المصفوفة (array) لانك اذا لم تقم بذلك سيحدث خطأ لنفترض انك قمت بتعريف check لياخذ قيمة 1 و ان ال array لا تحتوى على عنصر رقم 1 وان اصغر قيمة هى مثلا 5 كما فى المثال الخاص بكم ستجد ان القيمة التى سيتم ارجاعها من هذه الدالة هى 1 وهذا خطأ لذلك قمنا باخذ اول قيمة فى المصفوفة ثانيا ستجد انى قمت باضافة abs(check) بدلا من check لان اول قيمة فى المصفوفة من الممكن ان تكون سالبة لذلك ستكون اصغر من اى قيمة موجبة اخرى ولن يتحقق الشرط لذلك قمنا باضافة ذلك. اخيرا ستجدنى قمت باضافة هذا السطر if (check < 0) return 0; لانه فى حالة ان المصفوفة كانت جميعها ارقام سالبة فيجب ان يقوم بارجاع 01 نقطة
-
السلام عليكم الان عند الانتهاء من تنفيذ موقع وأريد رفعه عل جوجل ما هي الخطوات اللازمه لفعل ذلك اي اريد شراء دومين مدي الحياه لاستضافه الموقع فما الخطوات اللازمه لذلك1 نقطة
-
في الكود الخاص بك، تحتاج إلى إعادة تعليق return لأنه تم تعليقه حاليًا. دون عبارة return، فإن الدالة minpositive لا تقوم بإرجاع أي قيمة، وبالتالي فإن القيمة التي يتم طباعتها في main() لن تكون محددة، وستعرض قيمة عشوائية من الذاكرة. لحل هذه المشكلة والحصول على أصغر عنصر موجب في المصفوفة، يمكنك استخدام قيمة افتراضية تمثل أصغر عدد ممكن، ثم تحديث هذه القيمة أثناء المرور عبر المصفوفة. في حالة عدم وجود عناصر موجبة في المصفوفة، يمكنك إعادة هذه القيمة الافتراضية كنتيجة. الكود الخاص بك بعد التعديل #include <iostream> using namespace std; int minpositive(int nums[], int size) { int check = 1; // قيمة افتراضية تمثل أصغر عدد ممكن for (int i = 0; i < size; i++) { if (nums[i] > 0 && check > nums[i]) { check = nums[i]; } } return check; } int main() { int numbers[] = { -10, -20, 15, 100, 10, 5, -50, 0 }; // 5 int numssize = sizeof(numbers) / sizeof(numbers[0]); cout << minpositive(numbers, numssize) << "\n"; return 0; }1 نقطة
-
بطبع يمكنك التعديل كما تريد ساعطيك مثال علي جدول المستخدمين ويمكنك تطبيقه علي اي جدول لديك في المشروع يمكنك ايجاد جميع الجداول داخل هذه المسار database/migrations ستجد جميع الجداول الخاصه بالمشروع من ضمنهم جدول المستخدمين عند انشاء مشروع لارافل جديد يكون جدول المستخدمين بهذه الشكل <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateUsersTable extends Migration { public function up() { Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); } public function down() { Schema::dropIfExists('users'); } } اذا كنت تريد تغير اسم الجدول بدالا من users الي اي شئ اخر مثلا students فكل ماعليك تغير كلمة users الي students بهذه الطريقه <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateUsersTable extends Migration { public function up() { Schema::create('students', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); } public function down() { Schema::dropIfExists('users'); } } هذه بنسبه لاسم الجدول ماذا عن الحقول ايضا الحقول يمكنك تغيرها هذه الاعمده تمثل جميع الحقول الخاصه بالجدول $table->id(); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); علي سبيل المثال اذا كنت تريد تغير حقل البريد (email) بحقل الهاتف سيكون الجدول بهذه الشكل <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateUsersTable extends Migration { public function up() { Schema::create('students', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); } public function down() { Schema::dropIfExists('users'); } } في النهايه عليك ترحيل الجداول من جديد ببسااطه عن طريق تشغيل هذه الامر في الترمينال الخاص بمشروعك php artisan migrate:fresh في نهاية عند تغير اسماء الحقول او الجداول او الكلاس في لارافل توصي ببعض القواعد التي من المفترض اتباعها لتحسين مشروعك هذه بعض القواعد 1. التسميات الواضحة والمفهومة: اختر أسماءً تعكس الغرض والمعنى الحقيقي للجداول والحقول. على سبيل المثال، اسم الجدول يجب أن يوضح ماهية البيانات التي يحتويها مثل users, posts, comments، وهكذا. 2. التسميات بالجمع: استخدم صيغة الجمع لتسمية الجداول التي تحتوي على مجموعة من البيانات، مثل الجدول users بدلاً من user. 3. Snake Case للجداول والحقول: استخدم تنسيق Snake Case (أو الحروف الصغيرة والشرطات السفلية بين الكلمات) لتسمية الجداول والحقول. مثال: first_name, last_name, created_at. 4. التسميات التي تبدأ بالفعل: للحقول التي تعبر عن حالة أو إجراء، يُفضل أن تبدأ بفعل. مثال: is_active, has_comments. 5. التسميات الواضحة للعلاقات: عند استخدام العلاقات بين الجداول، اختر أسماء توضح نوع العلاقة. مثال: user_id للمفتاح الخارجي في جدول يشير إلى جدول users. 6. تجنب الاختصارات غير المفهومة: تجنب استخدام الاختصارات التي لا يمكن فهمها بسهولة. استخدم الكلمات الكاملة للتسميات لجعل الكود أكثر وضوحًا وقابلية للفهم. 7. التسميات المفصولة: استخدم الشرطة السفلية أو الشرطة لفصل الكلمات في الأسماء بدلاً من استخدام الفاصلة أو الفراغ. مثال: created_at, user_id. 8. الحفاظ على التوحيد: حافظ على توحيد التسميات في جميع أجزاء التطبيق لتسهيل فهم وصيانة الكود. 9. باستخدام هذه القواعد، يمكنك تحسين قراءة وصيانة تطبيقك وتجنب المشاكل التي قد تنشأ من تسميات غير1 نقطة
-
السلام عليكم جميعا , لدي استفسار عن ما مدى صعوبة الامتحان النهائي , مما جعلني مترددا للغاية رغم تمكني من الفهم الجيد للأساسيات فهل هناك عدد محدود لعدد المحاولات بعد الفشل و هل الفشل في الاختبار ام نهائي (أي لا يمكن اعادة الاختبار بعد الفشل) و مامدى صعوبة الامتحان , شكرا مقدما!1 نقطة
-
وعليكم السلام! يبدو أنك ترغب في نشر موقعك على الإنترنت وتحديد دومين له. إليك خطوات عامة لتحقيق ذلك: 1. اختيار مزود خدمة استضافة: قم بالبحث عن شركات استضافة مواقع على الإنترنت. بعض الشركات المشهورة تشمل Bluehost، HostGator، SiteGround، وغيرها. قارن الخدمات والأسعار لاختيار الخيار الذي يناسب احتياجاتك. 2. شراء حزمة استضافة: اختر حزمة استضافة تناسب متطلبات موقعك. قد تحتاج إلى حزمة تشمل مساحة تخزين كافية، باندويث كافية، وإمكانيات أمان ملائمة. 3. اختيار اسم النطاق (دومين): بعد شراء حزمة الاستضافة، قم بشراء اسم النطاق الذي ترغب في استخدامه لموقعك. يجب أن يكون اسم النطاق فريدًا، ويمكنك البحث عن توافر الاسم المطلوب. 4. ربط النطاق بالاستضافة: بعد شراء اسم النطاق وحزمة الاستضافة، اربط النطاق بحساب الاستضافة. يمكنك الحصول على معلومات الخوادم (nameservers) من شركة الاستضافة وتكوينها في حساب النطاق. 5. تثبيت نظام إدارة المحتوى (CMS): قد تستخدم نظام إدارة المحتوى مثل WordPress، Joomla، أو Drupal. قم بتثبيته على الاستضافة الخاصة بك وقم بتكوينه وفقًا لاحتياجات موقعك. 6. تصميم وتطوير الموقع: ابدأ في تصميم وتطوير موقعك باستخدام الثيمات والإضافات المناسبة. قم بإضافة المحتوى والصور اللازمة. 7. اختبار الموقع: قم بفحص الموقع للتأكد من أن جميع الصفحات تعمل بشكل صحيح وأن التنسيق والأمان جيدين. 8. تقديم الموقع لمحركات البحث: سجل موقعك في Google Search Console و Bing Webmaster Tools لتسهيل فهرسة محتواك من قبل محركات البحث. بعد اتباع هذه الخطوات، ستكون قد أنشأت وربطت موقعك على الإنترنت وتم استعداده للفهرسة على محركات البحث.1 نقطة
-
أولاً عليك إضافة الدالة الصحيحة هنا: list_tasks.set_defaults(func = controller.check_task) لتصبح: list_tasks.set_defaults(func=controller.display) بعد ذلك عليك عدم وضع فواصل بين بيانات المهمة في ملف Task.py أي بدلاً من: return f'{self.title} , {self.description} , {self.start_date} , {self.end_date} , {self.done}' يصبح: return f'{self.title}, {self.description}, {self.start_date}, {self.end_date}, {self.done}' فهناك مسافة إضافية في نهاية السلسلة، والتي لا يمكن لـ "date.fromisoformat()" تحليلها. بعد ذلك احذف ملف taks.txt ثم أضف مهمة والتجربة مرة أخرى.1 نقطة
-
سيتم سؤالك في الأمور المهمة التي لها علاقة بصميم محتوى الدورة والتخصص الخاص بها، وأيضًا في المسارات التي قمت بإنهائها بحد أدنى 4 مسارات، أيضًا سيتم سؤالك حول المشاريع العملية التي قمت بتنفيذها في الدورة. وذلك خلال محادثة مدتها 30 دقيقة، بعد ذلك سيتم تحديد مشروع التخرج للعمل عليه. لذا أمور مثل تخصيص المتصفح لن يتم سؤالك عنها بالطبع.1 نقطة
-
بالنسبة للطرق التي ذكرتها لانستطيع القول أن أحدها أفضل من الأخرى بشكل مطلق , فهذه الطرق جميعها تعتمد على الجمهور الكبير و المحتوى الذي تقدمه, وهي في البداية قد تكون بطيئة ريثما يصبح لديك متابعين و مهتمين و عليك دائما أن تستمر و ترتقي بجودة المحتوى الذي تقدمه , سواء على انستغرام أو يوتيوب أو مواقع التواصل الأخرى أو على المدونة الخاصة بك. فالربح باستخدام هذه الطرق يكون عن طريق الإعلانات التي ستعرضها على حسابك أو المنتجات التي ستروج لها و لذلك يجب أن يكون لديك جمهور مستهدف و يجب أن تعمل دائما على زيادة هذا الجمهور و أن تصنع محتوى يناسب هذا الجمهور. بالإضافة الى الطرق التي ذكرتها يمكنك العمل كمستقل على الانترنت إذا كنت تمتلك خبرة في تطوير التطبيقات ,أو إذا كنت تمتلك مهارات إدارية تستطيع أن تشكل فريق برمجي و تقوم أنت بجلب العملاء ووتتعاقد معهم و تسند العمل للفريق. و لكن هنا عليك البحث عن أشخاص خبيرين في مجال التطوير و أمناء و تستطيع الاعتماد عليهم, ويمكنك القراءة عن كيفية البدء بهذا العمل من هنا و عليكأن تعلم أن هذه الطرق تتطلب الوقت والجهد قبل أن تحقق دخلاً كافياً، ومعظمها يتطلب تعلم مهارات جديدة والاستمرارية في العمل.بالإضافة إلى الابتكار والقدرة على التكيف مع التغييرات في السوق واحتياجات الجمهور.1 نقطة
-
إطار Angular هو إطار عمل مفتوح المصدر يُستخدم في إنشاء تطبيقات لمنصات متعددة مثل الويب وويب الأجهزة المحمولة وكذلك تطبيقات سطح المكتب، وهو أحد أشهر أطر العمل في مجال تطبيقات وحيدة الصفحة. سننشئ في هذه السلسلة تطبيقًا للتدوين باستخدام إطار أنجولَر في الواجهة الأمامية، ونستخدم Google cloud Firestore كقاعدة بيانات، كما سنتعلم كيفية نقل التطبيق إلى منصة Firebase وتشغيله عليها. سيحتوي التطبيق على المزايا التالية: لغة التصميم Material Design. إضافة تدوينة جديدة. تعديل تدوينة حالية. حذف تدوينة حالية. المصادقة مع حساب جوجل. المصادقة المبنية على الدور role-based. ترقيم التدوينات. التعليقات على التدوينات. خيار مشاركة التدوينة على الشبكات الاجتماعية. وسنتعلم المفاهيم التالية حول أنجولَر: استخدام Cloud Firestore مع تطبيق Angular. مكتبة Angular Material وإطار عمل Bootstrap. الاستمارات المبنية على القوالب template-driven. التحقق من الاستمارات. الأنابيب المخصصة Custom pipes. الصنف Auth-guards. الاستيثاق Authentication والتصريح Authorization. تسجيل الدخول بجوجل باستخدام Firebase. ترقيم الصفحات من جانب العميل Client-Side pagination باستخدام ترقيم ngx. يمكن الاطلاع على نسخة عاملة من التطبيق في firebaseapp. ينبغي أن تكون في نهاية السلسلة قد أتقنت مفاهيم إطار عمل Angular المتقدمة، واستطعت إنشاء تطبيقات ويب تفاعلية باستخدام Angular وقاعدة بيانات Firebase. هذا المقال جزء من سلسلة عن بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore مقدمة في بناء تطبيقات الويب باستخدام إطار العمل Angular وقاعدة بيانات Firestore. بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore - إضافة التدوينات وعرضها. بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore - تعديل التدوينات. بناء مدونة باستخدام إطار العمل Angular وقاعدة بيانات Firestore - إضافة الاستثيثاق. نشر مدونة مبنية عبر Angular على Firebase. مصطلحات أساسية لابد التطرق إلى المصطلحات التي سنتعرض لها خلال هذه السلسلة والمرور عليها سريعًا، إذ لن نتعمق فيها ونشرحها أثناء العمل على بناء التطبيق لذلك ننصحك بالقراءة عنها ما أمكن ليسهل عليك فهم عملية بناء المدونة. التطبيقات وحيدة الصفحة التطبيقات وحيدة الصفحة Single Page Application هي تطبيقات ويب تحتوي على صفحة HTML واحدة، تُحمَّل من الخادم عند إطلاق التطبيق لأول مرة عند، ثم يتولى المتصفح كل شيء بعدها، ولا يرسل الخادم أي HTML بعد التحميل الأول للصفحة، بل يطلب المتصفح بيانات من الخادم ويرسلها الخادم إليها، فتُعاد كتابة البيانات دون إعادة تحميل الصفحة. ولا تُحدَّث الصفحة في التطبيقات وحيدة الصفحات إلا عند طلب بيانات جديدة من الخادم -انتبه من أن التحديث refresh يختلف عن إعادة التحميل reload- وذلك لنحصل على تجربة مستخدم أفضل. ما هي Typescript؟ وفقًا لتعريفها في موسوعة حسوب، فهي لغة برمجة مفتوحة المصدر من تطوير شركة Microsoft، تُعَد امتدادًا وتوسعةً للغة JavaScript، حيث أضافت العديد من المزايا إليها، خاصّةً دعم الأنواع types الذي يُساعد على تجنّب الأخطاء والعلل البرمجيّة وتوفير شيفرة برمجية نقية قابلة للقراءة أكثر من شيفرة JavaScript العادية. ما هو Angular؟ هو إطار عمل مفتوح المصدر للغة جافاسكربت تقوم جوجل على تطويره ومتابعته. يسمح لنا Angular بإنشاء تطبيقات ويب من جانب العميل client-side باستخدام لغة Typescript، ويُستخدم في إنشاء التطبيقات وحيدة الصفحة، كما يسمح ببناء تطبيقات لمنصات التشغيل المختلفة مثل الويب وويب الأجهزة المحمولة mobile web، وتطبيقات الويب الأصلية native web apps، وتطبيقات سطح المكتب الأصلية كذلك. يحتوي إطار عمل Angular على العديد من المزايا، من أهمها ما يلي: الكفاءة العالية في التنفيذ. قابلية التوسع. معماريته قائمة على المكونات components. فيه دعم مضمَّن للاستمارات forms وعمليات التحقق validation فيها. فيه دعم متعدد المنصات للتطوير. مفتوح المصدر ومدعوم من قِبل جوجل. تُبنى معمارية إطار Angular على المكونات، أي أنه component-based، وسيمر كل مكون خلال سلسلة من الأحداث من إنشائه حتى تدميره، وتلك الأحداث المحورية في حياة المكونات تعرِّفها خطافات دورة الحياة lifecycle hooks، وتوفر مكتبة Angular الأساسية مجموعةً من واجهات خطاطيف دورات الحياة التي تسمح لنا بالاستفادة من تلك اللحظات الرئيسية في دورة حياة كل مكون. تحتوي كل واجهة من تلك الواجهات على تابع خطاف hook method وحيد يكون اسمه هو اسم الواجهة مسبوقًا بـ ng، ويوفر Angular ثمانية توابع لخطاطيف دورات الحياة، كما هو موضح في الجدول أدناه، وهو جدول مستوحى من https://angular.io/guide/lifecycle-hooks. table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } الخطاف الغرض والتوقيت ngOnChanges() الاستجابة عند ضبط Angular لخصائص دخل البيانات المربوطة data-bound أو إعادة ضبطها. يستقبل التابع كائن SimpleChanges من قيم الخاصية الحالية والسابقة، ويُستدعى قبل ngOnInit() وعند تغير واحد أو أكثر من خصائص دخل data-bound. ngOnInit() تهيئة الموجِّه directive أو المكون بعد عرض Angular لخصائص data-bound لأول مرة، وضبطها لخصائص دخل المكوِّن. يُستدعى مرة واحدة، بعد أول ngOnChanges(). ngDoCheck() اكتشاف التغييرات التي لا يستطيع Angular أن يكتشفها بنفسه، واتخاذ إجراء بشأنها. يُستدعى في كل مرة يُلتقط فيها تغير ما، مباشرة بعد ngOnChanges() و ngOnInit(). ngAfterContentInit() الاستجابة بعد أن يرسل Angular المحتوى الخارجي ليُعرض في المكون أو العرض الذي يوجد فيه الموجِّه. يُستدعى مرة واحدة بعد أول ngDoCheck(). ngAfterContentChecked() الاستجابة بعد تحقق Angular أن المحتوى تم عرضه في الموجِّه أو المكون. يُستدعى بعد ngAfterContentInit() وفي كل استدعاء ngDoCheck() يتبعه. ngAfterViewInit() الرد بعد تهيئة Angular لعروض المكون والعروض الفرعية أو العروض التي فيها الموجِّه. يُستدعى مرة واحدة بعد أول ngAfterContentChecked(). ngAfterViewChecked() الرد بعد تحقق Angular من عروض المكون والعروض الفرعية أو التي يوجد فيها الموجِّه. يُستدعى بعد ngAfterViewInit() وفي كل استدعاء ngAfterViewChecked() يتبعه. ngOnDestroy() التنظيف قبل تدمير Angular للموجِّه/المكون. ألغ الاشتراك في العناصر المرئية observables وافصل معالجات الأحداث event handlers لتجنب حدوث تسريب في الذاكرة. يُستدعى قبل تدمير Angular للموجِّه/المكون. يحتوي الموجِّه على نفس مجموعة خطاطيف دورات الحياة التي للمكوِّن، ولا ينفِّذ أي منهما كل الخطاطيف التي لديه، إذ لا يُستدعى التابع الخطاف إلا عند تعريفه. ينبغي أن تكون لديك معرفة أساسية بإطار عمل Angular كما ذكرنا في مقدمة المقالة، وإلا سيستلزم الأمر أن تُراجع سلسلة أساسيات Angular.js في أكاديمية حسوب أولًا. ما هي Firebase؟ هي منصة تطوير لتطبيقات الويب التي تُستخدم على الحواسيب الشخصية والأجهزة المحمولة، وقد طورتها شركة Firebase في عام 2011، ثم استحوذت عليها شركة جوجل في 2014، وتُعَد هذه المنصة من فئة تطبيقات الواجهة الخلفية التي تُقدَّم كخدمة Backend as a Service، واختصارها Baas. توفر منصة Firebase عدة مزايا لتطوير التطبيقات، أهمها ما يلي: سرعة بناء التطبيقات دون الحاجة لإدارة البنية التحتية لها، إذ توفر مزايا مثل التحليلات وقواعد البيانات والرسائل وتقارير التعطل crash reports. مدعومة من قِبل جوجل: بما أن جوجل استحوذت على المنصة، فهي توفر لها بنيةً تحتيةً قويةً وقابلةً للزيادة حتى في حالة التطبيقات الكبيرة. منصة واحدة لعدة منتجات تعمل معًا بشكل أفضل: تعمل منتجات Firebase بكفاءة وهي مستقلة عن بعضها، لكن تستطيع مشاركة البيانات فيما بينها، وهذا يعطيها مزية عن غيرها من التطبيقات التي لا تجمعها منصة واحدة. تدعم Firebase عدة منصات تشغيل مثل iOS وأندرويد والويب ويونِيتي Unity وكذلك C++، وهي منصة شاملة تحتوي على ثمانية عشر منتجًا، مقسمة إلى ثلاثة تصانيف: بناء تطبيقات أفضل. تطوير جودة التطبيق. نمو الشركة القائمة على ذلك التطبيق. يوضح الجدول التالي بعض المنتجات من هذه التصانيف، ويُرجع إلى https://firebase.google.com/products-build للحصول على التفاصيل الكاملة لكل منتج منها: بناء تطبيقات أفضل تطوير جودة التطبيق نمو الشركة Cloud Firestore Crashlytics Google Analytics Cloud Storage Performance Monitoring Predictions Authentication Test Lab Cloud Messaging Hosting App Distribution Remote Config أما خطط الأسعار في منصة Firebase فهي كما يلي: خطة Spark: هذه الخطة مجانية ومناسبة للشركات الصغيرة والتطبيقات المخصصة للعرض فقط demo apps. خطة Blaze: هذه الخطة يزيد الاشتراك فيها مع زيادة الاستهلاك، وهي مناسبة للشركات الكبيرة. يُرجع إلى معلومات التسعير المفصلة في موقع firebase لمزيد من التوضيح. ما هي Angular Material؟ تُعَد Angular Material مكتبة مكونات لواجهة المستخدم UI Components لإطار عمل Angular، ومبنية على مواصفات لغة التصميم المادي material design الخاصة بجوجل، وتوفر لنا مكونات حديثة لواجهة المستخدم للعمل على عدة منصات، حيث تم تحسينها لأجل Angular، ويمكن إدراجها في تطبيقاته بسهولة. كذلك تدعم هذه المكتبة جميع المتصفحات الحديثة، وتوفر سمات themes مضمنة فيها لتحسين مظهر التطبيقات، مع توفيرها لسمات مخصصة أيضًا. إعداد بيئة تطوير Angular يجب تثبيت البرامج التالية لنستطيع التطوير باستخدام إطار Angular: Node.js. Angular CLI. Visual Studio Code. Node.js تتصرف Node مثل خادم للتطوير، حيث تسمح لتطبيق Angular بالعمل على الحاسوب المحلي. ثبِّت النسخة طويلة الدعم من Node -النسخة الحالية وقت كتابة هذه الكلمات هي 14.18.0- والتي تناسب نظام تشغيلك من موقعها، وذلك التثبيت سيثبّت بالتبعية مدير الحزم NPM. افتح الطرفية وشغِّل الأمر التالي لمعرفة إصدار node: node -v وهذا الأمر أيضًا لنعرف إصدار NPM: npm -v انظر لقطة الشاشة أدناه للتوضيح: نلاحظ أن إصدار NPM هنا هو 6.14.15. Angular CLI أداة Angular CLI هي واجهة غير رسومية -تعمل من سطر الأوامر- تسمح لنا بتطوير تطبيقات Angular ووضع هياكلها البنيوية وتهيئتها، فهي توفر الأدوات والأوامر التي نحتاج إليها من أجل تسهيل تطوير تطبيقات Angular. افتح نافذة الطرفية وشغّل الأمر التالي لتثبيت Angular CLI: npm install -g @angular/cli يُستخدم الأمر أدناه لمعرفة إصدار Angular CLI: ng version الإصدار الحالي لها وقت كتابة هذه الكلمات هو الإصدار 12.2.7، انظر إلى الصورة أدناه: Visual Studio Code بيئة التطوير Visual Studio Code هي بيئة تطوير مجانية ومفتوحة المصدر طورتها مايكروسوفت، ويمكن استخدامها كمحرر برمجي خفيف، وتدعم تطوير البرمجيات بلغات C++ و C# وجافا و PHP وبايثون و Typescript وغيرها، وهي متاحة لأنظمة التشغيل الثلاثة المشهورة: ويندوز وماك ولينكس. سنستخدم هذه البيئة في تطوير تطبيقات Angular في هذه السلسلة، إذ أنها من أشهر بيئات التطوير المستخدمة في كتابة برامج Angular، رغم دعم بيئات تطوير أخرى له، مثل Sublime Text و Atom و Webstorm وغيرها. والآن، ثبِّت النسخة الأخيرة من بيئة Visual Studio Code التي تناسب نظام تشغيلك من موقعه. إنشاء تطبيق Angular جديد ستجد الشيفرة المصدرية للتطبيق التالي متاحة في هذا المستودع في github، فتستطيع نسخ المستودع والاسترشاد بالشيفرة أثناء إنشائنا للتطبيق. كذلك، ستحتاج إلى حساب Gmail لتستطيع الدخول إلى Firebase، وذلك إضافة إلى إعداد بيئة تطوير Angular. انتقل الآن إلى المجلد الذي تريد إنشاء المشروع الجديد فيه، وافتح نافذة الطرفية -أو command prompt على ويندوز- وشغّل الأمر التالي لإنشاء تطبيق Angular جديد باسم blogsite: ng new blogsite --routing=false --style=scss غيّر المجلد وانتقل منه إلى مجلد الجذر root للمشروع، وهو blog site في حالتنا، وافتح المشروع في VS code من خلال تشغيل مجموعة الأوامر التالية: cd blogsite code . إعداد Firebase سننشئ مشروعًا على firebase، ونعِدّ قاعدة بيانات Google cloud firebase لها، وسنستخدم قاعدة البيانات تلك لتطبيق Angular، كما هو مبين في الخطوات التالية: إنشاء مشروع على Firebase اتبع الخطوات التالية لإنشاء مشروع جديد على Firebase: اذهب إلى https://console.firebase.google.com/ وسجل الدخول باستخدام حساب gmail. اضغط على زر Create a Project. أدخل اسم المشروع، يمكنك إعطاؤه أي اسم تريد، وسنستخدم الاسم blogsite في حالتنا. اضغط بعدها على Continue. انظر الصورة أدناه: عطِّل زر Enable Google Analytics for this project الذي في الصفحة التالية، ثم اضغط على Create Project. انظر الصورة: إضافة إعدادات Firebase إلى التطبيق سننشئ تطبيق ويب لمشروع Firebase، وسنضيف بيانات الإعدادات لتطبيق Firebase إلى تطبيق Angular، هذا يسمح له بالاتصال بتطبيق Firebase. في صفحة overview للمشروع، اضغط على أيقونة الويب التي تحمل رمز وسم إغلاق في HTML، كما هو موضح في الصورة أدناه: ثم في الصفحة التالية، أدخل اسمًا مستعارًا nickname، وتستطيع هنا اختيار أي اسم تريد، وقد استخدمنا blogsite، وهو نفس اسم مشروعنا. اضغط الآن على زر Register app كما هو موضح في الصورة أدناه: انسخ الكائن firebaseConfig من وسم <script>، والصق الشيفرة المنسوخة إلى src/environments/environment.ts كما هو موضح في الشيفرة أدناه: firebaseConfig: { apiKey: "AIzaSyCxqWK4SVAAJkozEkURuteREIW9197z6-s", authDomain: "blogsite-b165e.firebaseapp.com", databaseURL: "https://blogsite-b165e.firebaseio.com", projectId: "blogsite-b165e", storageBucket: "blogsite-b165e.appspot.com", messagingSenderId: "1057108181105", appId: "1:1057108181105:web:ac5bbb18e5f34c7e575bd0" } بالمثل، الصق الشيفرة إلى src/environments/environment.prod.ts، واستورد ثابت البيئة environment constant إلى src/app/app.module.ts كما هو موضح في الشيفرة أدناه: ... import { AppComponent } from './app.component'; import { environment } from 'src/environments/environment'; ... والآن، اضغط على Continue to the console في صفحة Firebase. إنشاء قاعدة بيانات Firebase السحابية انتقل إلى صفحة Project Overview لمشروع Firebase الخاص بك، واختر Database من قسم Develop الموجود في القائمة على اليسار، ثم اضغط على زر Create database. في نافذة إنشاء قاعدة البيانات Create database المنبثقة، اختر "البدء في وضع الاختبار" Start in test mode واضغط Next، ثم اترك القيمة الافتراضية لموقع Cloud Firestore كما هي واضغط Done. هكذا نكون قد أعددنا قاعدة بيانات Cloud Firestore لمشروع Firebase، انظر الصورة أدناه: يُنصح بإعداد قاعدة البيانات في وضع الاختبار test mode لعينات التطبيقات رغم أن هذا سلوك غير صحيح من الناحية الأمنية، حيث نرى من الرسالة المعروضة أنه بإمكان أي أحد يملك مرجعًا إلى قاعدة البيانات أن يقرأها ويعدّل فيها لمدة ثلاثين يومًا. سنغير هذه القاعدة في الجزء الأخير من الكتاب لنسمح بتعديل قاعدة البيانات من قِبل المستخدمين المصرح لهم فقط. ربط Firebase مع تطبيق Angular افتح نافذةً طرفيةً جديدةً في المجلد الجذر للمشروع لنستخدمها في تنفيذ جميع أوامر Angular، ونفِّذ الأمر التالي لتثبيت حزم Firebase الخاصة به: npm install firebase @angular/fire --save استورد المكتبات الموجودة في AnkitSharma، كما هو موضح أدناه. import { AngularFireModule } from '@angular/fire'; import { AngularFirestoreModule } from '@angular/fire/firestore'; @NgModule({ ... imports: [ // other imports AngularFireModule.initializeApp(environment.firebaseConfig), AngularFirestoreModule, ], ... }) تهيئة مكتبة التنسيق لتطبيق Angular يمكن الاعتماد على مكتبة Material Design أو مكتبة Bootstrap وذلك لإضافة التنسيقات لتطبيقات جاهزة بسهولة للتطبيق وسنشرح كيفية إضافة هاتين المكتبتين إلى تطبيقنا. إضافة مكتبة Angular Material نفِّذ الأمر التالي في الطرفية لتثبيت حزم Angular Material وحزمة تطوير المكونات Component Dev Kit CDK، ومكتبات تحريك Angular -أو Angular animations libraries-. npm install --save @angular/material @angular/cdk @angular/animations بعد نجاح تثبيت هذه الحزم، استورد المكتبات إلى ملف src/app/app.module.ts كما يلي: import {BrowserAnimationsModule} from '@angular/platformbrowser/animations'; @NgModule({ ... imports: [ ... BrowserAnimationsModule, ], }) توفر حزمة Angular Material أربعة سمات themes افتراضيًا، هي ما يلي: deeppurple-amber.css. indigo-pink.css. pink-bluegrey.css. purple-green.css. لإدراج سمة في تطبيق Angular، نحتاج إلى إضافة مرجع في الملف style.scss، فإذا أردنا إضافة السمة الثانية من القائمة أعلاه -indigo-pink.css- على التطبيق كله، فإننا سنضيف السطر التالي في ملف styles.scss: @import "~@angular/material/prebuilt-themes/indigo-pink.css"; أما لتعلم المزيد حول سمات material فيُنظر في دليل موقع Angular. سننشئ بعد ذلك وحدةً جديدةً نضع فيها المكونات المتعلقة بحزمة Angular Material، وذلك بكتابة الأمر التالي في الطرفية: ng g m ng-material افتح ملف ng-material.module.ts، واستبدل بالشيفرة الموجودة فيه الشيفرة التالية: import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatDividerModule } from '@angular/material/divider'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; import { MatMenuModule } from '@angular/material/menu'; import { MatProgressSpinnerModule } from '@angular/material/progressspinner'; import { MatSelectModule } from '@angular/material/select'; import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatToolbarModule } from '@angular/material/toolbar'; import { MatTooltipModule } from '@angular/material/tooltip'; @NgModule({ declarations: [], imports: [ CommonModule, MatToolbarModule, MatButtonModule, MatCardModule, MatInputModule, MatIconModule, MatDividerModule, MatMenuModule, MatSelectModule, MatSnackBarModule, MatProgressSpinnerModule, MatTooltipModule, ], exports: [ CommonModule, MatToolbarModule, MatButtonModule, MatCardModule, MatInputModule, MatIconModule, MatDividerModule, MatMenuModule, MatSelectModule, MatSnackBarModule, MatProgressSpinnerModule, MatTooltipModule, ] }) export class NgMaterialModule { } استوردنا في الشيفرة السابقة جميع الوحدات الخاصة بمكونات Angular Material التي سنستخدمها في هذا التطبيق، وستعمل وحدة أخرى مستقلة بذاتها على جعل التطبيق سهل الصيانة. استورد الوحدة NgMaterialModule إلى الملف app.module.ts كما يلي: import { NgMaterialModule } from './ng-material/ng-material.module'; @NgModule({ ... imports: [ ... NgMaterialModule, ], }) إضافة إطار Bootstrap إطار العمل Bootstrap هو إطار CSS يُستخدم في بناء تطبيقات ويب متجاوبة responsive وموجهة للأجهزة المحمولة أولًا mobile-first، وهو إطار عمل مفتوح المصدر يستخدمه مطورو الويب بكثرة، ويُعد لهذا أشهر إطار CSS لتطوير الويب، وآخر إصدار منه وقت كتابة هذه الكلمات هو الإصدار 5.1، وهو يدعم آخر الإصدارات المستقرة من متصفحات الويب المشهورة، بما في ذلك إنترنت إكسبلورر 10-11، ومتصفح Edge. لتثبيت إطار bootstrap في تطبيقنا، نشغِّل الأمر التالي: npm install bootstrap --save كذلك، نضيف مرجعًا عامًا global إلى إطار bootstrap في ملف src/styles.scss كما يلي: @import "~bootstrap/dist/css/bootstrap.css"; تشغيل التطبيق من الخادم افتح نافذةً طرفيةً جديدةً وشغِّل الأمر التالي: ng serve -o ستوفر حزمة Angular CLI الآن التطبيق على العنوان localhost:4200، والذي سيُفتح بواسطة المتصفح الافتراضي لديك، كما يظهر في الصورة التالية: سيعيد التطبيق الآن عملية التصريف compiling وإعادة التحميل كلما تغير الملف، وسنترك الخادم يعمل ونعود لمتابعة إنشاء بقية المكونات. خاتمة تعرفنا في هذا الفصل إلى إطار العمل Angular وإمكانية استخدامه في إنشاء تطبيقات ويب وحيدة الصفحة، وكيفية إعداد بيئة العمل المناسبة اللازمة لإنشاء مثل تلك التطبيقات؛ أما في المقال التالي فسنستخدمه لبناء مدونة على أساس تطبيق عملي عليه، وكيفية تخصيصها وإضافة الوظائف اللازمة لها من إنشاء للتدوينات ونشرٍ لها، ثم تحريرها وحذفها، والصلاحيات اللازمة لذلك لأنواع المستخدمين. اقرأ أيضًا تهيئة بيئة تطبيقات Angular ونشرها على الويب إضافة التنقل وإدارة البيانات في تطبيق Angular كيفية استعمال Angular في بناء تطبيقات الويب1 نقطة