المحتوى عن 'index'.



مزيد من الخيارات

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المُحتوى


التصنيفات

  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • نصائح وإرشادات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • التجارة الإلكترونية
  • مقالات عامة

التصنيفات

  • PHP
    • Laravel
    • ووردبريس
  • جافاسكريبت
    • Node.js
    • jQuery
    • AngularJS
    • Cordova
  • HTML5
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • سي شارب #C
    • منصة Xamarin
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • برمجة أندرويد
  • لغة Swift
  • لغة R
  • سير العمل
    • Git
  • صناعة الألعاب
    • Unity3D
  • مقالات عامّة

التصنيفات

  • تجربة المستخدم
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
    • كوريل درو
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • مقالات عامّة

التصنيفات

  • خواديم
    • الويب HTTP
    • قواعد البيانات
    • البريد الإلكتروني
    • DNS
    • Samba
  • الحوسبة السّحابية
    • Docker
  • إدارة الإعدادات والنّشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • مقالات عامة

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • استسراع النمو
  • المبيعات

التصنيفات

  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • مقالات عامة

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
  • أندرويد
  • iOS
  • macOS
  • ويندوز

التصنيفات

  • شهادات سيسكو
    • CCNA
  • شهادات مايكروسوفت
  • شهادات Amazon Web Services
  • شهادات ريدهات
    • RHCSA
  • شهادات CompTIA
  • مقالات عامة

أسئلة وأجوبة

  • الأقسام
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة البرمجة
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات
    • أسئلة الشهادات المتخصصة

التصنيفات

  • ريادة الأعمال
  • العمل الحر
  • التسويق والمبيعات
  • البرمجة
  • التصميم
  • DevOps

تمّ العثور على 4 نتائج

  1. بدأنا في الدرس السابق بتخصيص الموقع عبر تعريف الثوابت وإنشاء ملفات header.php و footer.php والعمل على ملفات searchform.php و sidebar.php. الخطوة 2.6- كتابة ملفِّ index بعد إضافة كلِّ تلك الملفّات للقالب، حان الوقت للعمل على الصفحة الرئيسية للموقع، طبعا نحن نتحدّث عن ملفّ index.php. قم بإنشائه داخل مجلّد قالبنا ثم أضف إليه الكود التّالي: <?php get_header(); ?> <?php get_sidebar(); ?> <?php get_footer(); ?> دعنا الآن نلقي نظرةً على رئيسيّة الموقِع لنرى التغييرات التي طرأت عليها. لاحظ أنّه ما عدا القائمة الجانبيّة، فإنّ كلًّا من رأس وتذييل القالب في مكانها المحدّد. لإضافة بعض المحتوى إلى رئيسيّة الموقع افتح ملفّ index.html وقم بنسخ المنطقة المحدّدة بين “blog area section” إلى غاية وسم غلق div ذو الكلاس box-layer align-center page-nav ثمّ ألصِق كلّ ذلك في ملفِّ index.php مباشرةً تحت دالّة get_header ستحصل على شيء مشابه لهذا: <!-- BLOG AREA --> <section> <hr class=&"no-margin&" /> <div class=&"blog-container section-content&"> <div class=&"container&"> <div class=&"row&"> <div class=&"col-md-8&"> <ul class=&"negative-margin&"> <li> <h1><a href=&"single-blog.html&" class=&"gray&">Should I use a Pencil or a Ballpen?</a></h1> By <a href=&"#&">Sam Norton</a> / On July 20, 2014 / <a href=&"#&">Life Hacks</a> <figure> <img class=&"opacity-hover box-layer img-responsive&" src=&"images/thumb1.jpg&" alt=&"Pencil or Ballpen&" /> </figure> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.. <div class=&"btn-margin&"> <a href=&"single-blog.html&" class=&"btn btn-primary&">CONTINUE READING >>> </a> </div> </li> <li> <h1><a href=&"single-blog.html&" class=&"gray&">How to test your patience!</a></h1> By <a href=&"#&">Sam Norton</a> / On July 20, 2014 / <a href=&"#&">Life Tips</a> <figure> <img class=&"box-layer img-responsive&" src=&"images/thumb2.jpg&" alt=&"Pencil or Ballpen&" /> </figure> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.. <div class=&"btn-margin&"> <a href=&"single-blog.html&" class=&"btn btn-primary&">CONTINUE READING >>> </a> </div> </li> </ul> <div class=&"box-layer align-center page-nav&"> <ul class=&"btn&"> <li><a href=&"#&">Next Page >>> </a></li> </ul> </div> </div> الكود أعلاه سيقوم بعرض محتوًى ساكنٍ. لجعله ديناميكيٍّ سنستخدم حلقة تِكرارِ ووردبريس داخل منطقة التدوينات لعرضها بشكل متكرّرٍ مع محتوًى مختلفٍ. قم بتعويض الكود الذي نسخته سابقا بهذا الكود: <?php get_header(); ?> <!-- BLOG AREA --> <section> <hr class=&"no-margin&" /> <div class=&"blog-container section-content&"> <div class=&"container&"> <?php if (have_posts()) : ?> <div class=&"row&"> <div class=&"col-md-8&"> <ul class=&"negative-margin&"> <li> <?php while(have_posts()) : the_post(); ?> <h1><a href=&"<?php the_permalink(); ?>&" class=&"gray&"><?php the_title(); ?></a></h1> By <a href=&"<?php the_author_posts() ?>&"><?php the_author(); ?> </a> / On <?php echo get_the_date('F j, Y'); ?> / In <?php the_category(', '); ?> <?php if (has_post_thumbnail()) : ?> <figure> <a href=&"<?php the_permalink(); ?>&"><?php the_post_thumbnail('', array('class' => 'opacity-hover box-layer img-responsive')); ?></a> </figure> <?php the_excerpt(); ?> <div class=&"btn-margin&"> <a href=&"<?php the_permalink(); ?>&" class=&"btn btn-primary&">CONTINUE READING >>> </a> </div> </li> <?php endif; ?> <?php endwhile; ?> </ul> <?php global $wp_query; if ($wp_query->max_num_pages > 1) : ?> <div class=&"box-layer align-center page-nav&"> <ul class=&"btn&"> <li><?php previous_posts_link('<<< Previous Page', $wp_query->max_num_pages); ?></li> <li><?php next_posts_link('Next Page >>>', $wp_query->max_num_pages); ?></li> </ul> </div> <!-- end box --> <?php endif; ?> <?php endif; ?> </div> <aside> <div class=&"col-md-3 col-md-offset-1 margin-sidebar&"> <?php get_sidebar(); ?> </div> </aside> </div> </div> </div> </section> <?php get_footer(); ?> حلقة تِكرار ووردبريس عبارة عن أقسامِ أكواد تُستخدم من طرف ووردبريس لعرض المقالات. باستخدام حلقة التِّكرار هذه ووردبريس سيقوم بتناول كلِّ مقالٍ على حِدى ليتمّ عرضه في الصّفحة الحاليّة، بحيث يتم العرض وفق المعايير المحدّدة داخل وسوم حلقة التِّكرار. في العادة هذه الحلقة تأتي بهذه الأقسام من الأكواد: <?php if ( have_posts() ) { while ( have_posts() ) { the_post(); // // Post Content here // } // end while } // end if ?> الكود أعلاه يمثّل الشّكل القياسيِّ لحلقة تكرار ووردبريس لِعرض المقالات ومع ذلك مازال علينا استخدام الدوالّ التالية ضمن الحلقة: the_permalink : تقوم بعرضِ الرّابط الدائم للمقالِ الحاليِّ. the_title : تقوم باسترجاع عنوان المقالِ الحاليِّ. the_author_posts : تقوم بعرض عدد المقالات التّي قام الكاتب الحاليُّ بنشرها. the_author : تقوم بعرض اسم كاتبِ المقالِ الحاليِّ. get_the_date : تسترجع التوقيت الذي كُتب به المقالُ الحاليِّ. the_category : تعرض التصنيف أو التصنيفات التي ينتمي إليها المقال الحاليّ. the_post_thumbnail : تعرض الصّورة البارزة للمقالِ الحاليِّ كما تمّ تحديده في شاشة تعديل المقال (سنرى هذا بشكل مفصّلٍ بعد قليل). the_excerpt : تعرض المقتطف للمقالِ الحاليِّ. بعد تطبيقِ بعض الفلاتر عليها وتضمين auto-p عليها سنقوم بتحويل line-breaks إلى فقرة HTML فيما يتعلّق بالصّورة البارزة فسنستخدم الكود التّالي: <?php if (has_post_thumbnail()) : ?> <figure> <a href=&"<?php the_permalink(); ?>&"><?php the_post_thumbnail('', array('class' => 'opacity-hover box-layer img-responsive')); ?></a> </figure> <?php endif; ?> أوّلًا يتّم التأكّد من أنّ المقال يحتوي على صورةٍ بارزة، بعد ذلك إذا كان يحتوي على واحدةٍ، سنقوم بعرض رابط الموضوع إضافة إلى الصورة نفسها. لاحظ أنّنا أضفنا مصفوفة تحتوي على كلاس opacity-hover box-layer img-responsive. هذه طريقة لإضافة كلاس للصورة البارزة وجعلها تبدو بشكلٍ أجمل عن طريق إضافة: تأثيرٍ عند تمرير الفأرة فوقها، حدودٍ وظِلّ صندوق. لكنّ القيّام بكلّ هذا لن يقوم بعرض الصورة البارزة، يجب عليك أوّلًا تسجيل الصّورة البارزة. قم بنسخ الكود التّالي وأضِفه في ملفِّ functions.php. <?php /***********************************************************************************************/ /* Add Theme Support for Post Thumbnails */ /***********************************************************************************************/ if (function_exists('add_theme_support')) { add_theme_support('post-thumbnails'); set_post_thumbnail_size(742, 428); } ?> جيّد! الصورة البارزة ستظهر الآن. التّالي سيكون إضافة دالّةٍ تقوم بنزع العارِضات والنِّقاط بينهما من نهاية المقتطف التي تعرض فيه بطريقة افتراضية. دائما في ملفِّ functions.php أضف الكود التالي: <?php /***********************************************************************************************/ /* Remove the brackets, ellipsis and hellip on excerpt */ /***********************************************************************************************/ function trim_excerpt($text) { $text = str_replace('[hellip;]', '...', $text); return $text; } add_filter('get_the_excerpt', 'trim_excerpt'); ?> تاليًّا، سنقوم بتشغيل ترقيم الصّفحات التيّ قمنا بإضافتها سابقًا في ملفِّ index.php. الكود التّالي سيقوم باستدعاء wp_query، هناك كلاس محدّدة في نواةِ ووردبريس تتعامل مع تعقيدات استعلامات المقالات (أو الصفحات) لمدوّنة ووردبريس. هذه الكلاس بإضافة روابط لـ previous_post_link و next_posts_link function للتنقّل بين صفحاتِ مدوّنتك. ألقِ نظرةً على الكود التّالي: <?php global $wp_query; if ($wp_query->max_num_pages > 1) : ?> <div class=&"box-layer align-center page-nav&"> <ul class=&"btn&"> <li><?php previous_posts_link('<<< Previous Page', $wp_query->max_num_pages); ?></li> <li><?php next_posts_link('Next Page >>>', $wp_query->max_num_pages); ?></li> </ul> </div> <!-- end box --> <?php endif; ?> <?php endif; ?> كلمسةٍ ختاميِّة، قم بتضمين دالّة get_sidebar داخل وسم div ذو كلاس col-md-3 col-md-offset-1 margin-sidebar الكلُّ داخل وسمِ HTML5 aside، ستحصل كود مشابه للتّالي: <aside> <div class=&"col-md-3 col-md-offset-1 margin-sidebar&"> <?php get_sidebar(); ?> </div> </aside> كمراجعة نهائيّة ملفّ index.php يجب أن يحتوي على الكود أدناه، راجعه لتفادي أيّة أخطاء محتملة. <?php get_header(); ?> <!-- BLOG AREA --> <section> <hr class=&"no-margin&" /> <div class=&"blog-container section-content&"> <div class=&"container&"> <?php if (have_posts()) : ?> <div class=&"row&"> <div class=&"col-md-8&"> <ul class=&"negative-margin&"> <li> <?php while(have_posts()) : the_post(); ?> <h1><a href=&"<?php the_permalink(); ?>&" class=&"gray&"> <?php the_title(); ?> </a></h1> By <a href=&"<?php the_author_posts() ?>&"><?php the_author(); ?> </a> / On <?php echo get_the_date('F j, Y'); ?> / In <?php the_category(', '); ?> <?php if (has_post_thumbnail()) : ?> <figure> <a href=&"<?php the_permalink(); ?>&"><?php the_post_thumbnail('', array('class' => 'opacity-hover box-layer img-responsive')); ?></a> </figure> <?php the_excerpt(); ?> <div class=&"btn-margin&"> <a href=&"<?php the_permalink(); ?>&" class=&"btn btn-primary&">CONTINUE READING >>> </a> </div> </li> <?php endif; ?> <?php endwhile; ?> </ul> <?php global $wp_query; if ($wp_query->max_num_pages > 1) : ?> <div class=&"box-layer align-center page-nav&"> <ul class=&"btn&"> <li><?php previous_posts_link('<<< Previous Page', $wp_query->max_num_pages); ?></li> <li><?php next_posts_link('Next Page >>>', $wp_query->max_num_pages); ?></li> </ul> </div> <!-- end box --> <?php endif; ?> <?php endif; ?> </div> <aside> <div class=&"col-md-3 col-md-offset-1 margin-sidebar&"> <?php get_sidebar(); ?> </div> </aside> </div> </div> </div> </section> <?php get_footer(); ?> الخطوة 2.7- العملُ مع ملفِّ single.php الآن سنقوم بعرض كلِّ مقالةٍ بشكل منفصل، أنشئ ملفّ single.php ثمّ أضف له الكود التّالي: <?php get_header(); ?> <!-- BLOG AREA --> <section> <hr class=&"no-margin&" /> <?php if (have_posts()) : while(have_posts()) : the_post(); ?> <div class=&"blog-container section-content&"> <div class=&"container&"> <div class=&"row&"> <div class=&"col-md-8&"> <div class=&"box-layer custom-padding&"> <section> <h1><a href=&"<?php the_permalink(); ?>&" class=&"gray&"><?php the_title(); ?></a></h1> By <a href=&"<?php the_author_posts() ?>&"><?php the_author(); ?> </a> / On <?php echo get_the_date('F j, Y'); ?> / In <?php the_category(', '); ?> <?php if (has_post_thumbnail()) : ?> <figure> <a href=&"<?php the_permalink(); ?>&"><?php the_post_thumbnail('', array('class' => 'opacity-hover box-layer img-responsive')); ?></a> </figure> <?php the_content(); ?> <?php endif; ?> </section> <?php endwhile; ?> <?php endif; ?> <section> <div class=&"comment-section&"> <?php // If comments are open or we have at least one comment, load up the comment template if ( comments_open() || '0' != get_comments_number() ) : comments_template(); endif; ?> </div> </section> </div> <!-- RELATED ARTICLE AREA --> <section> <div class=&"box-layer related-articles custom-padding&"> <h3 class=&"align-center&">Related Articles</h3> <?php $current_categories = get_the_category(); $first_category = $current_categories[0]->term_id; $args = array( 'post_per_page' => 3, 'category__in' => array($first_category), 'post__not_in' => array($post->ID) ); $related_articles = new WP_Query($args); if ($related_articles->have_posts()) : ?> <ul> <?php while ($related_articles->have_posts()) : $related_articles->the_post(); ?> <li class=&"col-md-4&"> <?php if (has_post_thumbnail()) : ?> <figure> <a href=&"<?php the_permalink(); ?>&"><?php the_post_thumbnail('', array('class' => 'opacity-hover box-layer img-responsive')); ?></a> </figure> </figure> <a href=&"<?php the_permalink(); ?>&"><?php the_title(); ?></a> <?php endif; ?> </li> <?php endwhile; ?> <div class=&"clear&"></div> </ul> <?php endif; ?> <?php // Restore original Post Data wp_reset_postdata(); ?> </div> </section> </div> <!-- SIDEBAR AREA --> <aside> <div class=&"col-md-3 col-md-offset-1 margin-sidebar&"> <?php get_sidebar(); ?> </div> </aside> </section> <?php get_footer(); ?> ولإظهار التعليقات، قم بإضافة الكود التّالي: <section> <div class=&"comment-section&"> <?php if ( comments_open() || '0' != get_comments_number() ) : comments_template(); endif; ?> </div> </section> هذا الكود سيتحقّق إن كانت التعليقات مُتاحةً أو إن كانت هناك تعليقات ليقوم باستدعاء نموذج التعليقات (سنتناول ذلك لاحقا). الخطوة 2.8- العملُ مع ملفِّ page.php بعد أن أنهينا العمل على صفحة التّدوينة، سنتوجّه للعملِ على الصّفحات العادية. أنشئ ملفّ page.php ثم ألصق به الكود التّالي: <?php get_header(); ?> <!-- BLOG AREA --> <section> <hr class=&"no-margin&" /> <div class=&"blog-container section-content&"> <div class=&"container&"> <div class=&"row&"> <div class=&"col-md-8&"> <div class=&"box-layer custom-padding&"> <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?> <h3> <?php the_title(); ?> </h3> <?php if (has_post_thumbnail()) : ?> <figure> <a href=&"<?php the_permalink(); ?>&"><?php the_post_thumbnail('', array('class' => 'opacity-hover box-layer img-responsive')); ?></a> </figure> <?php endif; ?> <?php the_content(); ?> <?php endwhile; endif; //ends the loop ?> </div> </div> <!-- SIDEBAR AREA --> <aside> <div class=&"col-md-3 col-md-offset-1 margin-sidebar&"> <?php get_sidebar(); ?> </div> </aside> </section> <?php get_footer(); ?> مجدّدًا لا جديد في هذا الملفِّ عدا أنّه لا يحتوي على قسمٍ للتعليقات كونه سيعرضُ صفحةً عاديّة. في الملفّين المقبلين سنقوم باستخدام نموذجين مُدمجين في ووردبريس لعرض الصّفحات بِنسقٍ مختلفٍ. ترجمة -وبتصرّف- للمقال How to Convert a Static HTML Template into a Responsive WordPress Theme
  2. بعد أن تكلمنا في المقال السابق عن موضوع جملة الاستعلام في SQL وكيفية الاستعلام عن البيانات في جدول معين وترشيحها وفق الشروط التي نرغب بها، سنتناول في هذا المقال موضوع الفهارس Indexes وما تمثله في قاعدة البيانات، وما هي الفائدة منها. فهرس الجدول لو افترضنا وجود 1000 ملف ورقيّ غير مميزة عن بعضها وتحتوي على بيانات خاصة بطلاب جامعة، وهذه الملفات محفوظة في خزانتين منفصلتين، وأردنا الحصول على بيانات الطلاب الذين يسكنون منطقة معينة، ففي هذه الحالة سنضطر إلى فتح كل الملفات الموجودة في الخزانتيْن والبحث عن فئة الطلاب المستهدفة، وفرزهم والحصول على البيانات المطلوبة. ماذا لو كان لدينا عدد ملفات أكبر؟ سيزداد الوقت والجهد للحصول على البيانات، لذلك، فإن فكرة فهرسة الملفات في هذه الحالة ستكون أمرا جيدا بالتأكيد. سنُفهرِس مثلا الملفات حسب المكان ثم نحفظها في الخزانتين، بحيث تحتوي كل خزانة على بيانات الطلاب لمنطقة أو مناطق معينة. ثم داخل كل خزانة، نستطيع فرز الملفات وحفظها حسب الاسم مثلا. بتطبيق مفهوم الفهرسة، سنوفر على أنفسنا عناء البحث في الخزانتين، وسنقلل الوقت والجهد اللازمين لذلك. الفكرة الرئيسة للفهارس في قاعدة البيانات تدور حول المثال السابق، ففي ظل عصر تضخم البيانات، فإنه أصبح من الملح والضّروريّ وجود تقنيات لتسهيل الوصول السريع للمعلومة. ما هو الفهرس؟ لو أردنا مثلا أن نبحث عن اسم شخص في جدول الأشخاص Persons عبر استخدام الجملة التالية: SELECT * FROM Persons WHERE First_Name = "Ibrahim"; فإن نظام إدارة قاعدة البيانات سيمرّ على كل السجلات الموجودة في الجدول لترشيح السجلات وإرجاع تلك التي توافق الشرط في جملة where. ستظهر لنا مشكلة الوقت اللازم لتنفيذ جملة الاستعلام – وتزداد -كلما زاد عدد السجلات في الجدول، فلو كان لدينا مثلا مليون سجل في الجدول Persons، ولنفترض جدلاً أن النظام باستطاعته المرور على 10 آلاف سجل في الثانية، فإننا بحاجة إلى 100 ثانية لتنفيذ جملة الاستعلام السابقة. لحل المشكلة السابقة، فإن نُظم إدارة قواعد البيانات تقدم خاصية الفَهْرَسة. الفَهْرَسة هي ببساطة عبارة عن مؤشر يحتوي على نسخة من جزء من البيانات في الجدول، بحيث تقوم هذه النسخة من البيانات بمهمة “الدليل” أو “المُؤَشّر” الذي يسرع الوصول إلى البيانات الأصلية الكاملة الموجودة في الجدول، بحيث لا تحتاج المرور الكامل على كل الجدول (No Full Table Scan) عند البحث عن البيانات. يعدّ الفهرس عمليا طريقةً من طُرُق تراكيب البيانات، وهو عنصر مرتبط بوجود جدول في قاعدة البيانات، ولكن نستطيع تعريفه وحذفه منفصلا عن تعريف الجدول، ولا يكون له أي تأثير على نفس البيانات، فعند حذف الفهرس، فإن البيانات الموجودة في الجدول لا تتأثر. يكون الفهرس في أغلب أنظمة إدارة قواعد البيانات من نوع “B-Tree” ويأتي هذا الاسم من بنية البيانات Data structure التي تحمل نفس الاسم، وهو المفضل لأن تُطبقه على العمود الذي يحتوي قيمًا متنوعة وكثيرة مثل الرقم القومي للشخص، وليس من المفضل أن تطبق فهرس “B-Tree” على العمود الذي يحتوي عددًا قليلًا من القيم. توجد أنواع أخرى من الفهارس تُقدمها أنظمة إدارة قواعد البيانات مثل “Bitmap Index” و “Denes Index” ولكننا لن نتكلم عنها هنا لأنها خارج إطار موضوع المقال ولأنها تحتاج إلى مقالة منفصلة لشرحها. كيف تُعرَّف الفهارس؟ يُعرَّف الفهرس بطريقتيْن: تعريفه ضمنيًّا: تُبنَى الفهارس ضمنيا على الأعمدة التي يُطَبَّق عليها القيد الفريد وقيد المفتاح الرئيسي، فعند تعريف أحد القيود السابقة، يُبنى فهرس تلقائيًّا على العمود أو الأعمدة المُقيَّدة. تعريفه صراحةً: يُبنَى الفهرس بطريقة مباشرة على العمود أو الأعمدة الذي نرغب وذلك باستخدام جملة Create Index. على الرغم من أنه لا يوجد تعريف للفهرس في معايير SQL، إلا أن أغلب أنظمة إدارة قواعد البيانات تقدم الإمكانية لتعريف الفهرس ويتفق أغلبها على الصيغة العامة لذلك. الصيغة العامة لتعريف الفهرس: CREATE INDEX index_name ON table_name (column1, column2, ...); عند تعريف الفهرس، لابد أن يكون اسمه متوافقا مع القيود الخاصة بنظام إدارة قاعدة البيانات المستخدم، كما أنه يجب ألا يكون مُكررا، فأسماء الفهارس في قواعد البيانات يجب أن تكون فريدة ولا تتكرر. لإضافة فهرس باسم First_Name_idx على عمود First_Name في الجدول Persons ننفذ الجملة التالية: CREATE INDEX First_Name_idx ON Persons (First_Name); نستطيع تعريف فهرس فريد UNIQUE Index على عمود ممّا يجعل نظام قواعد البيانات يفحص التكرار داخل هذا النوع من الفهارس، حيث يتأكد النظام - في حالة إضافة أو تعديل قيمة لعمود عليه فهرس فريد - من أن هذه القيمة فريدة وغير مكررة؛ وفي حال كانت مكررة، يُرفَض هذا التغيير ويُظهَر خطأ في العملية. مثلا، لو أردنا أن نضيف فهرسًا فريدًا على عمود Age في الجدول Persons ننفذ الجملة التالية: CREATE UNIQUE INDEX Age_idx ON Persons (Age); نستطيع أيضا تعريف الفهرس على أكثر من عمود، كما في المثال التالي: CREATE UNIQUE INDEX Multiple_Columns_idx ON Persons (First_Name ,Age); عرّفنا في المثال السابق فهرسًا على عمودين، وفي هذه الحالة، فإن الفهرس سيفيد في تنفيذ جملة الترتيب Order by التي تحتوي العمود First_Name ثم عمود Age بنفس الترتيب. لن نستفيد من الفهرس السابق في حالة تنفيذ جملة الترتيب بترتيب مختلف للعمودين، ولن نستفيد أيضا منه في حالة تنفيذ جملة الاستعلام المشروطة بالبحث في هذين العمودين، حيث نحتاج لتعريف فهارس أخرى لكل عمود على حدة لتسريع عملية الاستعلام مع جملة Where. حذف الفهارس الصيغة العامة لحذف الفهرس كالتالي: DROP INDEX Index_Name ; فلحذف فهرس باسم Age_idx ننفذ الأمر التالي: DROP INDEX Age_idx ; متى نستخدم الفهارس؟ يفضل أن يتم بناء الفهارس على الأعمدة التي: يُبحث عنها في جملة Where. تُكتَب في جملة الترتيب Order By. تُكتَب في جملة التجميع Group By. تُستخدَم في جمل الربط Joins. تُستخدَم في الدوال الإحصائية مثل min وmax وmedian. متى نتجنب استخدام الفهارس؟ لا تعدّ الفهارس مناسبة على الأعمدة التي: - تحتوي على قيم فريدة قليلة مثل عمود الجنس (قيمتان فقط)، أو الحالة الاجتماعية. - نادرة الاستخدام في جمل الاستعلام SELECT. - التي تكون جزءًا من جدول ذي سجلات قليلة. ملاحظات هامة: لأن الفهرس عنصر مستقل في قواعد البيانات، وبناؤه وتعريفه يعدّ إضافة عليها، فلابد أن يدير مسؤول قاعدة البيانات الصلاحيات اللازمة لهذا الأمر بحيث لا يؤثر سلبا على أداء قاعدة البيانات. لا يعدّ الفهرس أساسيا في بناء الجدول في قاعدة البيانات، وعليه قد لا يحتوي الجدول على فهرس، وقد يحتوي على فهرس أو أكثر. نستطيع أن نُعرّف الفهرس عند بناء الجدول (في نفس جملة بناء الجدول)، ولكن من ناحية عملية، فإن إدارة الفهارس والتعامل معها تعدّ عملية مستمرة ومتكررة. تُبنَى الفهارس وتُحذَف حسب الحاجة للوصول إلى الكفاءة المطلوبة في قاعدة البيانات، لذلك تُقدم نُظم قواعد البيانات الأدوات اللازمة لقياس كفاءة جمل الاستعلام وقياس الحاجة لبناء الفهارس من عدمه. لا تُعَرِّف فهارس أكثر من حاجتك وخاصة في الجداول التي تحتوي سجلات كثيرة، فكما أن الفهارس تُسرع من عملية الوصول للبيانات، فإنها تؤثر سلبا على عمليات الإضافة والتعديل، فعند كل إضافة أو تعديل لابد من تعديل الفهرس ليتلاءم مع التغييرات الجديدة. عند تعريف الفهرس، فإن نظام قاعدة البيانات هو الذي يحافظ على الفهرس ويستخدمه تلقائيا، وعليه لا يُطلب من مسؤول قاعدة البيانات أو المبرمج أو حتى المستخدم أي إجراء آخر بعد تعريف وبناء الفهرس. يُسمى الفهرس الذي يُعرَّف على عمود واحد “فهرسا بسيطا”، والفهرس الذي يُعرَّف على أكثر من عمود يسمى “فهرسا مركبا”.
  3. يمكنك إنشاء الفهارس يدويا بإدراج جدول، ثم إدخال العناوين وأرقام الصفحات. لكن هذه الطريقة مطولة وتتطلب منك تحديث الجدول يدويا أيضًا كلما أجريت تغييرا على المستند. في هذا الدرس سنتعلم كيفية إنشاء فهارس تلقائية يمكن تحديثها بسهولة عند إجراء تعديلات على المستند، كما سنتعلم كيفية تخصيص هذه الفهارس وتنسيقها بعدة طرق. يُشار إلى الفهارس في النسخة العربية من مايكروسوفت وورد بمصطلح "جداول المحتويات"، وسنستخدم إصدار Word 2013 لشرح هذا الدرس، علما أنّ الخطوات لا تختلف بالنسبة للإصدارات الأقدم. إنشاء جدول محتويات تلقائيفي البداية، وقبل إنشاء الجدول، يجب أن تقوم بتطبيق أنماط العناوين؛ أي Heading 1 (عنوان 1)، Heading 2 (عنوان 2)، إلخ. يمكنك استخدام هذه العناوين حسب التنسيق الذي ترغب فيه. مثلا استخدم "عنوان 1" للمواضيع الرئيسية في المستند، "عنوان 2" للفقرات الرئيسية للموضوع، "عنوان 3" للفقرات الثانوية، وهكذا. لتطبيق أنماط العناوين: انقر فوق نص العنوان الذي تريد إظهاره في جدول المحتويات، ثم من تبويب الصفحة الرئيسية Home اختر نمط العنوان الذي تريده من قائمة أنماط العناوين. بعد أن تقوم بتطبيق جميع أنماط العناوين، انقر على المكان الذي تريد إنشاء الجدول فيه؛ غالبًا يكون في بداية المستند أو نهايته. اذهب إلى تبويب مراجع References ثم انقر على جدول محتويات Table of Content، واختر جدول تلقائي Automatic Table من القائمة المنسدلة. بهذه الخطوة تكون انتهيت من إنشاء جدول محتويات تلقائي. لنفترض مثلا أنّك قمت بالتعديل على المستند كحذف أو إضافة فقرة، تغيير العناوين، أو غيرها. يمكنك تحديث جدول المحتويات بسهولة بعد القيام بتلك التعديلات. اذهب إلى التبويب مراجع References ثم انقر على زر تحديث الجدول Update Table، واختر أحد الخيارين من مربع الحوار، إما تحديث الجدول بتغيير أرقام الصفحات فقط، أو تحديثه بأكمله. تخصيص جدول المحتويات أو تنسيقهيتيح برنامج وورد إمكانية التحكم في العديد من الخيارات لتخصيص الجدول، كإخفاء أرقام الصفحات، إضافة المزيد من مستويات العناوين، إلخ. يمكنك الوصول إلى هذه الخيارات عن طريق: تبويب مراجع References > جدول محتويات Table of Contents > جدول محتويات مخصص Custom Table of Contents معاينة نموذج الطباعة ومعاينة نموذج الويب.لإظهار أرقام الصفحات أو إخفائها.لإظهار خط المحاذاة بين أرقام الصفحات والعناوين أو إخفائها.لتغيير نمط خط المحاذاة.لتغيير تنسيق الجدول.لتغيير عدد المستويات المعروضة داخل الجدول.لإظهار العناوين في الجدول على شكل ارتباطات تشعبية لتسهيل الوصول إليها داخل المستند وذلك بمجرد النقر على العنوان. بإمكانك تحديد هذا الخيار إذا كنت تريد عرض المستند على الويب. أما إذا كنت تريد استخدام المستند لغرض الطباعة فقط، يمكنك الاكتفاء بخيار أرقام الصفحات.خيارات إضافية متعلقة بمستويات العناوين.لتعديل تنسيق المستويات في جدول المحتويات. إذا كان هذا الزر غير مفعل، غيّر التنسيقات Formats إلى من قالب From template. من مربع حوار تعديل Modify يمكنك أن تغيّر تنسيق النصوص داخل الجدول، كلون الخط، حجم الخط، المسافات البادئة، المسافات بين السطور، إلخ. من مربع الحوار هذا اختر المستوى الذي تريد تغيير تنسيقه ثم انقر على زر Modify. قم بإجراء التغييرات التي ترغب فيها ثم انقر موافق OK. بإمكانك تكرار هذه الخطوة على جميع المستويات في جدول المحتويات، وسيتذكر البرنامج هذا التخصيص كلما قمت بتحديث جدول المحتويات. خيارات متقدمةبإمكانك التحكم أكثر بمحتويات الجدول عن طريق الأنماط المخصصة، أو تعديل الجدول باستخدام رموز الحقول field codes. الأنماط المخصصة Custom Stylesلقد لاحظت أنّ إنشاء جدول المحتويات يعتمد على النصوص التي تم تنسيقها باستخدام أنماط العناوين الافتراضية (عنوان 1، عنوان 2، عنوان 3، إلخ)، مع ذلك تستطيع إنشاء نمط مخصص وتضمينه في جدول المحتويات. مثلًا، إذا كنت ترغب في إضافة مستوى رابع إلى الجدول يعرض وصفًا مختصرًا تحت كل عنوان، يمكنك استخدام نمط مخصص: قم بتحديد النص الذي تريد تضمينه في جدول المحتويات، ثم من معرض الأنماط اختر أنشئ نمطا Create a Style. قم بتسمية النمط بالاسم المرغوب، وليكن "ملخص" مثلا. ثم انقر OK. الآن اذهب إلى جدول المحتويات وانقر داخله لكي يتم تحديده. ثم من تبويب مراجع References انقر على جدول محتويات Table of Contents، ثم جدول محتويات مخصص Custom Table of Contents. انقر على زر خيارات Options ثم مرّر نزولا إلى النمط الذي قمت بإنشائه ("ملخص")، وفي حقل TOC level (مستويات جدول المحتويات) الخاص بهذا النمط قم بإدخال الرقم 4 (أو رقم المستوى الذي تريد إظهار الملخص فيه). لاحظ أن فقرة الملخص قد ظهرت في جدول المحتويات. بإمكانك التعديل على المسافة البادئة لتظهر بشكل مرتب. قم بتحديد النص في جدول المحتويات، ومن لوحة الأنماط انقر على السهم بجانب TOC 4 ثم اختر تعديل Modify. في مربع الحوار الذي سيظهر، انقر على زر تنسيق Format، ثم فقرة Paragraph.في الجزء الخاص بالمسافة البادئة Indentation قم بتغيير قيمة المسافة حسب ما تراه مناسبا. يمكنك استخدام المعاينة في أسفل مربع الحوار قبل تطبيقها. بعد اختيار المسافة البادئة المناسبة انقر OK. تعديل جدول المحتويات باستخدام رموز الحقل Field Codesتعمل رموز الحقل عمل الصيغ formulas في اكسل، حيث يمثل رمز الحقل الصيغة، وتمثل نتيجة الحقل القيمة التي تنتجها تلك الصيغة. تظهر رموز الحقل بين قوسين متعرجين {}، ويمكنك التبديل بين عرض رموز الحقل أو نتيجتها باستخدام المفتاحين Alt + F9. عندما تنقر فوق جدول المحتويات ثم تضغط على المفتاحين Alt + F9 سيظهر رمز الحقل بالشكل التالي: يمثل TOC اسم الحقل، ويستخدم هذا الرمز لبناء جدول محتويات. أما بقية الرموز فتسمى "رموز التبديل switches"، وهي التي تستخدم لتحديد خيارات بناء جدول المحتويات. مثلا الرمز o "1-3" يستخدم لإنشاء جدول من النصوص المطبقة عليها أنماط العناوين من 1 إلى 3. والرمز h يستخدم لعرض النصوص في الجدول على شكل ارتباطات تشعبية. أما الرمز t فيستخدم لإنشاء الجدول من أنماط العناوين المخصصة غير الأنماط الافتراضية، وهو النمط "ملخص" في مثالنا هذا (بإمكانك الاطلاع على المزيد من رموز الحقول الخاصة بجداول المحتويات عبر هذا الرابط). يمكنك استخدام رموز الحقول للتعديل على خيارات الجدول بشكل أسرع من مربعات الحوار. كما توفر رموز الحقول إمكانية تحكم أكبر في الخيارات المتاحة. مثلا، لو أردنا حذف رقم الصفحة من مستوى "الملخص" في جدول المحتويات. لا يمكننا فعل ذلك عن طريق مربع الحوار الخاص بجدول محتويات مخصص، لأنّه لا يوفر إمكانية حذف أرقام الصفحات لكل مستوى على حدة. لكن يمكننا فعل ذلك عن طريق رموز الحقول: قم بوضع المؤشر قبل رمز التبديل "t"، واكتب الرمز n\ ثم مسافة، ثم 4-4 ثم مسافة. إذ يستخدم الرمز n لحذف أرقام الصفحات من مستوى معين. وفي هذا المثال سيتم حذف رقم الصفحة من المستوى الرابع. انقر بزر الفأرة الأيمن على رمز الحقل، اختر تحديث الحقل Update Field، ثم اختر تحديث الجدول بأكمله Update entire table. بعد ذلك اضغط على المفتاحين Alt + F9 للعودة إلى نتيجة رمز الحقل (أي عرض الجدول): لاحظ اختفاء رقم الصفحة في المستوى الرابع. قد ترغب في بعض الأحيان بعرض ملخص أو وصف في جدول المحتويات ولا تريد إظهاره في المستند. بإمكانك فعل ذلك عن طريق الحقل TC. ضع المؤشر أمام العنوان الذي تريد عرض الملخص أو الوصف تحته في جدول المحتويات. من تبويب إدراج Insert انقر أجزاء سريعة Quick Parts ثم اختر حقل Field. من مربع الحوار الذي سيظهر اختر حقل TC. وفي خانة إدخال النص Text entry قم بكتابة النص الذي تريد ظهوره في جدول المحتويات. ثم أدخل رقم المستوى الذي تريد ظهور النص فيه واختر إخفاء رقم الصفحة Suppresses page number ثم انقر OK. وبذلك قمت بإضافة رمز الحقل. لعرض الرمز اذهب إلى تبويب الصفحة الرئيسية Home ثم انقر على زر علامة الفقرات. قم بإخفائه بالنقر على نفس الأيقونة من جديد. الآن اذهب إلى جدول المحتويات واضغط على المفتاحين Alt + F9. في رمز الحقل، ضع المؤشر قبل الرمز t ثم اكتب /f ثم مسافة، وذلك لعرض النص الذي أدخلته في حقل TC. قم بتحديث رمز الحقل ثم اضغط Alt + F9 لعرض جدول المحتويات. ستلاحظ ظهور النص الذي أدخلته في حقل TC في الجدول وعدم ظهوره في المستند. قم بإجراء التنسيقات المرغوبة. إذا كان المستند طويلًا جدا ويتكون من عدة فصول، يمكنك إنشاء أكثر من فهرس واحد في المستند، أي فهرس لكل فصل على حدة. وهذا ما سنشرحه في درس قادم إن شاء الله.
  4. أساسيات angularjs

    في الفصل السابق، المجالات، تعلّمنا أنّ Angular تقوم بإنشاء مجالٍ جديد في كلّ مرّةٍ يتمّ فيها استدعاء الباني الخاصّ بالمتحكّم عن طريق ng-controller. هناك حالاتٌ أخرى أيضًا تقوم فيها Angular بإنشاء مجالاتٍ جديدة، وربّما تكون الحالات الأكثر شيوعًا هي عند التّعامل مع مجموعاتٍ من كائناتٍ متشابهة، كما سنرى في هذا الفصل. لا تملك Angular مكوّنًا اسمه Collection على عكس Backbone، ولكنّ دعم Angular الواسع للمجموعات ذات الكائنات المتشابهة يستحقّ إفراد فصلٍ كاملٍ لها، كما سنرى الآن. التهيئةقمنا سابقًا بتضمين المكتبة المستضافة عند Google في رأس مستندات HTML الخاصة بأمثلة الفصول السابقة، وسنضيف في هذا الفصل أسلوب Bootstrap في تنسيق الجداول والقوائم لإعطائها مظهرًا أجمل. <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.js"></script>بعد ذلك نقوم بتحميل وحدة app بتمرير اسمها إلى التّوجيه ng-app. يمكنك اختيار أيّ اسم للوحدة بدلًا من app. <body ng-app="app"> <!-- الأمثلة توضع هنا --> </body>كما شرحنا سابقًا، سنحتاج إلى إضافة بعض الشّيفرات المعيارية لنتجنّب استخدام الوحدات في أمثلة هذا الدرس، وسنغطّي ذلك المفهوم في الفصل القادم في هذا الكتاب. angular.module('app', []); angular.module('app').config(['$controllerProvider', function($controllerProvider) { $controllerProvider.allowGlobals(); }]);نحن جاهزون الآن لنتقدّم في استكشافنا التّفاعليّ للمجموعات (collections) والمرور على العناصر (iteration) ولـAngular. المرور على العناصرفي JavaScript المعتادة، عندما تمرّ على عناصر مجموعة من كائنات متشابهة عن طريق حلقة for، قد تقوم بالتّصريح عن متغيّر محلّيّ ليحتفظ بمرجعٍ للعنصر الحاليّ، على سبيل المثال: var items = [{name: "Item 1"},{name: "Item 2"}]; for (var i = 0; i < items.length; i++) { var item = items[i]; } document.body.innerHTML = item.name;الناتج Item 2ربما تظنّ (تتمنّى؟ تأمل؟ ترجو؟) أن يكون المتغيّر item في المثال السابق موجودًا ضمن مجال أسماءٍ تُنشئه JavaScript عند كل دورةٍ لحلقة for، للأسف، JavaScript لا تقوم بذلك كما يبيّن السطر الأخير في المثال السّابق.فالمتغيّر item متاح للاستخدام خارج الحلقة، لقراءة المزيد عن هذه النقطة، يُرجى مراجعة دليل Mozilla في JavaScript. ولكنّ Angular تتجنّب هذا المأزق عن طريق دعمها الدّاخليّ للمرور على العناصر.وكي نرى كيف تقوم بذلك لنقم أوّلًا بنقل المصفوفة items إلى داخل متحكّم. function ItemsController($scope) { $scope.items = [ {name: 'Item 1', price: 1.99}, {name: 'Item 2', price: 2.99} ]; }تخيّل لو أنّ items مجموعةٌ غير معروفة الطّول، ونحتاج إلى المرور على جميع عناصرها، وإظهار قيمة العنصر name لكلّ عنصرٍ فيها، ما الذي سنقوم به؟ ng-repeatرأينا سابقًا كيف تقوم Angular بإنشاء مجالٍ للعبارات لحمايتنا من إنشاء المتغيّرات في مجال JavaScript العام، وبطريقةٍ مماثلةٍ لذلك، يقوم التّوجيه ng-repeat بحمايتنا من الحالة التي رأيناها في المثال الأوّل، وذلك بإنشاء مجال Angular لكلّ دورة تكرار للحلقة. <ol ng-controller="ItemsController"> <li ng-repeat="item in items" ng-bind="item.name"></li> <li ng-bind="item.name"></li> </ol>الناتج ْ1. Item 1 2. Item 2 3. كما ترى، العنصر item غير متاحٍ خارج حلقة ng-repeat. تقوم ng-repeat بإنشاء مجالٍ ابنٍ جديد لكلّ عنصرٍ جديد من المجموعة مع الخصائص التي تحددها العبارة المحددة للمجموعة. في مثالنا السّابق، كان اسم الخاصّيّة هو item ولكن يمكن أن نستبدله بأيّ اسم. جرّب تغيير المثال السّابق وغيّر item إلى شيءٍ آخر، جرّب i أو x. عناصر الكائناتالتركيب النّحوي (مفتاح، قيمة) للكائن يسمح لك بالمرور على عناصر الكائنات. سيفيدك ذلك إن كنت تحتاج إلى كتابة محتوى كائنٍ ما بشكلٍ كامل في العرض. <table class="table table-condensed"> <tr ng-repeat="(propertyName, propertyValue) in {b: 'two', a: 1.0, c: 3}"> <td ng-bind="propertyName"></td> <td ng-bind="propertyValue"></td> </tr> </table>الناتج b two a 1 c 3ماذا لو أردنا استخراج عنصرٍ معيّن؟ كيف نقوم باستخراج عنصرٍ له اسمٌ محدّد من جميع الكائنات الموجودة في المجموعة؟ التركيب النحوي item in items الذي استخدمناه في مثال ng-repeat السابق، يشبه كثيرًا باني القائمة، ولكنّ ng-repeat لا تسمح للأسف بإرجاع أيّ شيءٍ غير عناصر الكائن أو المصفوفة في الطرف الأيمن للعبارة، لنحاول على أيّ حال. <ol ng-controller="ItemsController"> <!-- Invalid code! Syntax error, because 'for' is not supported! --> <li ng-repeat="item.name for item in items" ng-bind="item.name"></li> </ol> لم تعمل كما أخبرتك. باني القائمة الحقيقيّ يسمح لك بإرجاع أيّ شيء تريده من التعداد الأصليّ، عادةً باستخدام الكلمة المفتاحيّة for. تقدّم CoffeeScript مثالًا ممتازًا على ذلك. index$تقوم ng-repeat بإسناد الرقم التسلسلي للعنصر الحالي إلى متغيّرٍ خاصٍ هو index$ وذلك إضافةً إلى المتغيّر الّذي يحوي قيمة العنصر. في المثال التّالي سنقوم بإعادة اختراع العجلة، وسننشئ طريقةً جديدةً لكتابة قوائم HTML المرقّمة، حيث سنستخدم قيمة المتغيّر index$ في الإخراج. <div ng-controller="ItemsController"> <div ng-repeat="item in items"> {{$index + 1}}. {{item.name}} </div> </div>الناتج 1. Item 1 2. Item 2لنحاول الآن القيام باستخدامٍ متداخلٍ للتّوجيه ng-repeat. أوّلًا، لننشئ هيكل نموذج بياناتٍ أكثر تعقيدًا حيث يحوي كلّ عنصرٍ في الطبقة العلويّة مصفوفةً من الأبناء. function ItemsController($scope) { $scope.items = [ {name: 'Item 1', items: [ {name: 'Nested Item 1.1'}, {name: 'Nested Item 1.2'} ] }, {name: 'Item 2', items: [ {name: 'Nested Item 2.1'}, {name: 'Nested Item 2.2'} ] } ]; }والآن لنقم بإدخال حلقةٍ داخل أخرى، ستقوم الشّيفرة التّالية بإضافة اسم كلّ عنصرٍ إلى قائمةٍ مرقّمة. <div ng-controller="ItemsController"> <ol> <li ng-repeat="item in items"> {{item.name}} <ol> <li ng-repeat="item in item.items"> {{item.name}} </li> </ol> </li> </ol> </div>الناتج 1. Item 1 1. Nested Item 1.1 2. Nested Item 1.2 2. Item 2 1. Nested Item 2.1 2. Nested Item 2.2ولكن ماذا لو أردنا إنشاء عدّاداتٍ متداخلة؟ كيف سنمنع المتغيّر index$ الّذي تمّت تحديد قيمته في الحلقة الخارجيّة من أن يتمّ تظليله بالمتغيّر ذي الاسم نفسه الّذي تُنشئه الحلقة الدّاخليّة؟ ng-initربّما تتذكّر من الفصل الأول، المبادئ، أنّ Angular تسمح لنا بتهيئة متغيّرات المجال في منطقة العرض باستخدام التّوجيه ng-init. حلّ مشكلتنا يكمُن في استخدام ng-init للقيام بإعادة تعيين، أو عمل اسمٍ مستعارٍ، لمتغيّر الحلقة الخارجيّة index$ قبل أن يتمّ تظليله. <div ng-controller="ItemsController"> <div ng-repeat="item in items" ng-init="outerCount = $index"> {{outerCount + 1}}. {{item.name}} <div ng-repeat="item in item.items"> {{outerCount + 1}}.{{$index + 1}}. {{item.name}} </div> </div> </div>الناتج 1. Item 1 1.1. Nested Item 1.1 1.2. Nested Item 1.2 2. Item 2 2.1. Nested Item 2.1 2.2. Nested Item 2.2لا تكتفي ng-repeat بالمتغيّر index$ فهي تقوم بإسناد عددٍ من المتغيّرات البوليانيّة في كلّ دورٍ للحلقة، وهي: first$ وmiddle$ وlast$ وeven$ وodd$. يمكنك تجربة كلِّ واحدٍ منها ضمن المثال التّالي، وهذا المثال يستخدم التّوجيه المفيد ng-class حيث يتمّ وسم الخانة باللون الأخضر عندما تكون العبارة الشّرطيّة محقّقة. هل يمكنك اكتشاف الطّريقة الّتي تجعل العنصرين الأوّل والأخير فقط موسومين باللون الأخضر؟ (ملاحظة: ستحتاج إلى إضافة العمليّة ! فقط.) <ol> <li ng-repeat="val in [1,2,3,4,5]"> <span class="label label-default" ng-class="{'label-success': $middle}"> {{val}} </span> </li> </ol>هل لاحظت شيئًا عند استخدام المتغيّرين even$ وodd$؟ تقوم Angular بتحديد قيمة المتغيّرات وفق الطّريقة التّقليديّة التي تعتمد بدء التّرقيم من الصّفر في حلقات for. قد لا يبدو الأمر مثيرًا للاهتمام للوهلة الأولى، ولكن لو لاحظت جيّدًا فترقيم العناصر يبدأ من الصّفر بينما يبدأ ترقيم القائمة المرتّبة من الواحد، وهذا يعني أنّ المتغيّرين even$ وodd$ سيعملات بشكلٍ معاكسٍ لاسمهما بالنّسبة لترقيم القائمة. التفردكملاحظةٍ جانبيّة، يجب عليك الانتباه عند استخدام المتغيّرات البدائيّة (primitives) داخل ng-repeat بأن لا تكون جميع عناصر المجموعة متفرّدة، أي أنّه لا يوجد أي تكرار لأي قيمة في المجموعة، ومن يحدّد تطابق العناصر هو عمليّة المساواة المتشدّدة === في JavaScript. المساواة المتشددةلنقم ببعض التّجارب لإنعاش معلوماتنا في كيفيّة عمل عمليّة المساواة الصّارمة === في JavaScript. يختبر القالب التّالي المساواة بين أعدادٍ، سلاسل نصّيّةٍ وكائنات. <table class="table table-condensed"> <tr> <td>1 === 1</td> <td>{{1 === 1}}</td> </tr> <tr> <td>'1' === '1'</td> <td>{{'1' === '1'}}</td> </tr> <tr> <td>1 === '1'</td> <td>{{1 === '1'}}</td> </tr> <tr> <td>{} === {}</td> <td>{{ {} === {} }}</td> </tr> <tr> <td>{name: 1} === {name: 1}</td> <td>{{ {name: 1} === {name: 1} }}</td> </tr> </table>الناتج 1 === 1 true '1' === '1' true 1 === '1' false {} === {} false {name: 1} === {name: 1} falseبيّنّا بأنّ التّساوي بين عناصر المجموعة مرفوض، وسيبيّن المثال التّالي الخطأ الّذي سينتج عن تكرار العدد 1 في المجموعة. <ol> <!-- Invalid code! Duplicate element error, because '1' is repeated! --> <li ng-repeat="val in [1,2,1]" ng-bind="val"></li> </ol>قم بتعديل المثال السّابق، واستخدم خليطًا من الأعداد والسّلاسل النّصّيّة بدلًا من الأعداد فقط، جرّب المصفوفة التّالية [1,2,'1']. ماذا كانت النّتيجة؟ والآن حاول تغييرها باستخدام الكائنات بدلًا من الأعداد، جرّب المصفوفة التّالية [{name: 1},{name: 2},{name: 1}]. ستحتاج إلى تغيير العبارة "ng-bind="val إلى "ng-bind="val.name لتتمكّن من رؤية القيم. track byإنّ حلّ مشكلة مصفوفة الأعداد السّابقة يكمُن في إضافة تعليمة track by إلى عبارة ng-repeat وذلك لكي يتمّ تجاوز اختبار المساواة الّذي يتمّ القيام به تلقائيًّا للعناصر. يمكنك تتبّع عناصر المجموعة باستخدام أيّ متغيّر متفرّد (لا تتكرّر القيم الّتي يأخذها عند كلّ عنصر)، وإن لم يكن لديك متغيّر متفرّد (فالقيم العدديّة الموجودة داخل المصفوفة ليست كذلك)، يمكنك استخدام المتغيّر index$. <ol> <li ng-repeat="val in [1,2,1] track by $index" ng-bind="val"></li> </ol>الناتج 1. 1 2. 2 3. 1يجب عليك استخدام متغيّرات متفرّدة في نماذج كائناتك كلّما أمكنك ذلك، كأن تستخدم معرّفًا رقميًّا متفرّدًا يتمّ إنشاؤه عن طريق مخزن بيانات في الـbackend أو عن طريق نوعٍ ما من مولّد UUID في طرف المستخدم. إن لم يكن لديك مفرٌّ من استخدام المتغيّر index$ فكن حذرًا لأنّ التّغييرات في المجموعة قد تٌسبّب مشاكل في الأحداث الخاصة بالصفحة. توابع الاستدعاء الخلفيتسهّل Angular الحصول على مرجعٍ لعنصرٍ ما في المجموعة لتتمكّن من استخدامه داخل متحكّم ما. ليس عليك إلّا أن تمرّر عنصر المجموعة إلى تابع استدعاءٍ خلفيّ (callback) في التّوجيه الذي يسمح بتمرير تابع استدعاءٍ خلفيّ، مثل ng-click. على سبيل المثال، لنقم بكتابة شيفرة للسماح للمستخدم بحذف أحد عناصر المجموعة، سنحتاج إلى تعريف تابع استدعاء خلفيّ في المتحكّم بحيث يقبل مرجع العنصر المُراد حذفه كوسيطه الوحيد. يمكننا تسمية هذا التّابع بأي اسم، لنقم بتسميته destroy (سيكون هذا ملائمًا له). function ItemsController($scope) { $scope.items = [ {id: 1, name: 'Item 1'}, {id: 2, name: 'Item 2'}, {id: 3, name: 'Item 3'}, {id: 4, name: 'Item 4'} ]; $scope.destroy = function(item) { var index = $scope.items.indexOf(item); $scope.items.splice(index, 1); }; }قد تبدو طريقة حذف العنصر من المصفوفة في الشّيفرة السابقة مزعجة بعض الشيء إلا أنها الطريقة المُتّبعة في JavaScript للقيام بذلك، ولن تُسبّب أي خطأ مع Angular في ذلك. كُلّ ما بقي هو إضافة "(ng-click="destroy(item إلى عنصرٍ ما داخل الحلقة. كما يشير التّوجيه ng-click، فالزر هو الخيار الأفضل، ولكن لا بدّ من الإشارة إلى أنّه يمكننا استخدام التّوجيه ng-click مع أيّ عنصرٍ قابلٍ للنّقر. <div ng-controller="ItemsController"> <h4 ng-pluralize count="items.length" when="{'one': '1 item', 'other': '{} items'}"> </h4> <table class="table table-condensed"> <tr ng-repeat="item in items"> <td ng-bind="item.name"></td> <td> <button class="btn btn-xs btn-default" ng-click="destroy(item)"> destroy </button> </td> </tr> </table> </div>أعتبرُ طريقة Angular في ربط تابع الاستدعاء الخلفيّ destroy مثالًا واضحًا على الأسلوب التّصريحيّ الذي تتبعه Angular. كفائدةٍ إضافيّة، يعرض المثال السّابق استخدام التّوجيه ng-pluralize لكتابة نصٍّ يميّز بين المفرد والجمع بشكلٍ مشروط، حسب عدد العناصر ضمن مجموعة ما. إعداد هذا التّوجيه صعبٌ قليلًا ولكنك قد تحتاج لاستخدامه. start- وend-رغم أنه ليس شائعًا، إلّا أنك قد ترغب بإخراج عناصر "إخوة" لكلّ عضوٍ في المجموعة. وكمثالٍ على ذلك قائمة الوصف، أو العنصر dl، الذي يحوي زوجي العناصر dt وdd. وهنا تظهر المشكلة، فالتّوجيه ng-repeat مُصمّمٌ ليتمّ تطبيقه على عنصر HTML واحد. ولكنّ حلّ هذه المشكلة هو بتوسيع نطاق التنفيذ لهذا التّوجيه ليشمل العديد من عناصر HTML باستخدام اللاحقتين start- وend-. <dl ng-controller="ItemsController"> <dt ng-repeat-start="item in items">name</dt> <dd ng-bind="item.name"></dd> <dt>price</dt> <dd ng-repeat-end ng-bind="item.price"></dd> </dl>هناك العديد من التّوجيهات الأخرى التي تستخدم اللاحقتين start- وend- وليس التّوجيه ng-repeat فقط، ويجب عليك أن تتأكد من عدم انتهاء التّوجيهات المخصصة التي تقوم بإنشائها (كما ستتعلم في فصل التوجيهات اللاحق) بأيٍّ من اللاحقتين start- وend-. خلاصةتدعم Angular المجموعات بقوّةٍ ومرونة عن طريق التّوجيه ng-repeat، وتسمح لنا ببناء واجهة مستخدمٍ سريعة لتطبيقات CRUD. تنتهي في هذا الفصل نظرتنا العامّة للوظائف الغنيّة في تطوير الويب التي يمكننا تعلّمها دون الغوص كثيرًا في بنية Angular الدّاخليّة. ولكن من الآن فصاعدًا، سنبدأ بالغوص أعمق فأعمق في Angular الموسّعة، ولنتمكّن من القيام بذلك سيكون علينا تعلُّم كيفيّة قيام Angular بإدارة المكوّنات. وسيغطّي الفصل القادم النّظام الّذي طوّرته Angular لذلك، الوحدات. ترجمة وبتصرّف للفصل الخامس من كتاب: Angular Basics لصاحبه: Chris Smith.