مطالب
آشنایی با Directive ها در AngularJs
اگر مطالعه ای اجمالی درباره مزیت‌ها و قدرت‌های فریم ورک Angular داشته باشید یکی از مواردی که بسیار جلب توجه می‌کند مبحث Directive‌ها است. به کمک Directive‌ها در Angular می‌توانید کد‌های HTML خود را توسعه دهید. این توسعه علاوه بر تعریف تگ‌های جدید، شامل توسعه کلاس‌ها و همچنین ویژگی‌های تگ‌های HTML نیز خواهد بود. کد‌های HTML شما بسیار خواناتر و از طرفی با قابلیت استفاده مجدد می‌شود. البته این پست فقط شروع به کار در این مقوله است زیرا مبحث Directive‌ها بسیار گسترده‌تر از آن است که بتوان مطالب آن را در  یک مقاله گنجاند.
برای شروع یک فایل جاوا اسکریپ ایجاد کرده و در ابتدای آن یک ماژول تعریف کنید:
var app = angular.module('myApp', []);
در این جا نام ماژول را myApp انتخاب کردم. حال یک Directive به نام angry (نام دیرکتیو‌ها را با حروف کوچک آغاز کنید )به صورت زیر ایجاد می‌کنیم:
app.directive('angry', function () {
    return {
        restrict: 'E',
        template: '<div style="color:red"> I am angry!</div>'
    }
})
 تابع سازنده Directive مورد نظر که یک آبجکت را برگشت می‌دهد شامل خواص زیر می‌باشد:
restrict: که چهار مقدار E و A و C و M را می‌پذیرد که به EACM نیز معروف هستند.
E: زمانی که قصد داشته باشیم یک المان جدید بسازیم از E به معنای element در restrict استفاده می‌کنیم(<my-directive></my-directive> 
 A: زمانی که قصد داشته باشیم Directive مورد نظر به عنوان Attribute در تگ‌ها استفاده شود از A به معنای Attribute در restrict استفاده می‌شود(<div my-directive="exp"></div> 
C: از C نیز برای تعریف Directive به عنوان مقادیر ویژگی کلاس استفاده می‌کنیم(<div class="my-directive: exp "></div> 
M: حالت M  نیز برای استفاده Directive در کامنت‌ها است(<!-- directive: my-directive exp -->  ).
در ادامه یک Directive  دیگر به نام happy می‌سازیم:
app.directive('happy', function () {
    return {
        restrict: 'A',
        template: '<div style="color:blue"> I am happy!</div>'
    };
})
تفاوت اصلی بین این دو Directive در نوع restrict آن‌ها می‌باشد. برای استفاده از این Directive‌ها در View می‌توان به صورت زیر عمل نمود:
<script type="text/javascript" src="~/scripts/Modules/module1.js"></script>

<div ng-app="myApp">
    <angry></angry>
    <div happy></div>
</div>
همان طور که می‌بینید دستور Directive اول که را با restrict از نوع E است می‌توان به عنوان یک تگ جدید استفاده کرد. دستور happy به عنوان ویژگی تگ div مورد استفاده قرار می‌گیرد(به دلیل اینکه restrict آن از نوع A است) که در نهایت خروجی ساده مثال بالا به صورت زیر خواهد بود:



ادامه دارد...
مطالب
شروع به کار با AngularJS 2.0 و TypeScript - قسمت اول - نصب پیشنیازها
AngularJS یک فریم ورک جاوا اسکریپتی، برای ساخت برنامه‌های تک صفحه‌ای سمت کاربر، توسط HTML ،CSS و جاوا اسکریپت است. این فریم ورک، حاوی اجزایی برای data binding، طراحی ماژولار، کار با سرویس‌های سمت سرور وب و امثال آن است. Angular 2 بازنویسی کامل نگارش 1 آن است و اهداف زیر را دنبال می‌کند:
- سرعت بالاتر بارگذاری و اجرای کدها
- استفاده از آخرین فناوری‌های وب مانند ES 6 و وب کامپوننت‌ها با پشتیبانی تا IE 9.
- سطح API آن با طراحی جدید آن، به شدت کاهش یافته و خلاصه شده‌است. همین امر یادگیری آن‌را نیز ساده‌تر می‌کند.

برای یادگیری Angular 2 نیازی به فراگیری Angular 1 نیست. در اینجا با آشنایی با TypeScript، به این نتیجه خواهید رسید که برنامه‌های Angular 2 چیزی بیشتر از یک مثال عملی TypeScript نیستند. زبان TypeScript، زبان اول و توصیه شده‌ی کار با Angular 2 است و مزیت آن دسترسی به تمام قابلیت‌های ES 6 است؛ با این تفاوت که کامپایلر TypeScript قادر است آن‌ها را به ES 5 یا نگارش فعلی جاوا اسکریپت که توسط تمام مرورگرها پشتیبانی می‌شود، ترجمه و تبدیل کند. به این نحو به یک طراحی شیءگرا، مدرن و با قابلیت نگهداری بالا خواهید رسید که با تمام مرورگرهای جدید نیز سازگار است.
بنابراین پیشنیاز‌های اصلی کار با Angular 2، فراگیری ES 6 و TypeScript هستند که دو سری ویژه و مختص به آن‌ها در سایت جاری تهیه شده‌اند:
«مبانی ES 6»
«مبانی TypeScript»

در این قسمت قصد داریم پیشنیازهای دریافت و نصب اجزاء و وابستگی‌های AngularJS 2 را به همراه TypeScript، در ویژوال استودیو 2015 بررسی کنیم. البته استفاده از ویژوال استودیو در اینجا ضروری نیست و اساسا AngularJS وابستگی به ویژوال استودیو ندارد. اگر به دنبال پشتیبانی بهتری از TypeScript هستید، VSCode رایگان، سورس باز و چند سکویی، گزینه‌ی بسیار بهتری است نسبت به ویژوال استودیوی کامل. البته این مورد تعجبی هم ندارد؛ از این جهت که VSCode با TypeScript نوشته شده‌است.


اهمیت آشنایی با npm

اگر در طی سال‌های اخیر با ویژوال استودیو کار کرده باشید، به طور قطع با NuGet نیز آشنا هستید. NuGet به عنوان یک package manager دات نتی شناخته می‌شود و کار آن دریافت وابستگی‌های یک پروژه، از مخزنی مشخص و نصب و به روز رسانی خودکار آن‌ها است. اما این روزها خارج از محیط توسعه‌ی مایکروسافت، مدیرهای بسته‌های دیگری مانند Bower نیز برای نصب و به روز رسانی بسته‌های front end مانند کتابخانه‌های CSS ایی و جاوا اسکریپتی، بسیار رواج پیدا کرده‌اند. Bower یکی از ابزارهای NodeJS است که توسط NPM یا NodeJS Package Manager نصب می‌شود. به این معنا که استفاده از Bower به معنای استفاده از NPM است. پیش از این از NPM صرفا جهت نصب بسته‌های مرتبط با NodeJS استفاده می‌شد، اما در طی یکسال اخیر، استفاده از NPM نیز برای مدیریت بسته‌های front end رواج پیدا کرده‌است و در صدر مدیر بسته‌های نصب کتابخانه‌های front end قرار دارد. همچنین در این حالت شما تنها نیاز به یک ابزار و یک فایل تنظیمات آن خواهید داشت، بجای استفاده از چندین ابزار و چندین فایل تنظیمات جداگانه. به علاوه این روزها انجام کارهای جدی جاوا اسکریپتی بدون دانش NPM دیگر میسر نیست. بهترین ابزارها، کامپایلرها، فشرده کننده‌های front end و امثال آن‌ها، تحت NodeJS اجرا می‌شوند. برای کار با AngularJS 2.0 و دریافت وابستگی‌های آن نیز استفاده از npm، روش پیش فرض و توصیه شده‌است.


کار با npm جهت دریافت وابستگی‌های کتابخانه‌های front end

برای کار با npm یا می‌توان از دستورات خط فرمان آن به صورت مستقیم استفاده کرد و یا از امکانات یکپارچگی آن با ویژوال استودیو نیز بهره گرفت که ما در ادامه از این روش استفاده خواهیم کرد. البته توانمندی‌های خط فرمان npm فراتر است از امکانات توکار VS.NET، اما در اینجا نیازی به آن‌ها نیست و هدف صرفا دریافت و به روز رسانی وابستگی‌های مرتبط است.
ویژوال استودیوی 2015 به همراه ابزارهای NodeJS ارائه می‌شود. اما مشکل اینجا است که این ابزارها هم اکنون قدیمی شده‌اند و تطابقی با آخرین نگارش ابزارهای NodeJS ندارند. برای نمونه حین نصب وابستگی‌‌های AngularJS 2.0 که یکی از آن‌ها RxJS است، یک چنین خروجی را در پنجره‌ی output ویژوال استودیو مشاهده می‌کنید:
 npm WARN engine rxjs@5.0.0-beta.6: wanted: {"npm":">=2.0.0"} (current: {"node":"v0.10.31","npm":"1.4.9"})
به این معنا که نگارش‌های اخیر RxJS نیاز به npm با نگارشی بیشتر از 2 را دارند؛ اما نگارش npm پیش فرض ویژوال استودیو 1.4.9 است (البته باید دقت داشت که من به روز رسانی دوم VS 2015 را هم نصب کرده‌ام). برای رهایی از این مشکل، تنها کافی است تا به ویژوال استودیو اعلام کنیم از نسخه‌ی اصلی خط فرمان npm، بجای نسخه‌ی پیش فرض خودش استفاده کند:


همانطور که در تصویر نیز ملاحظه می‌کنید، به مسیر Tools->Options->Projects and Solutions->External Web Tools مراجعه کرده و متغیر محیطی PATH ویندوز را به ابتدای لیست منتقل کنید. به این صورت ابزارهای به روز شده‌ی خط فرمان، مقدم خواهند شد بر ابزارهای قدیمی به همراه نگارش فعلی ویژوال استودیو.

البته فرض بر این است که آخرین نگارش nodejs را از آدرس https://nodejs.org/en دریافت و نصب کرده‌اید. با نصب آن، برنامه npm، در خط فرمان ویندوز به صورت مستقیم قابل استفاده خواهد بود؛ از این جهت که مسیر آن به PATH ویندوز اضافه شده‌است:



افزودن فایل project.json به پروژه

تا اینجا فرض بر این است که nodejs را از سایت آن دریافت و نصب کرده‌اید. همچنین متغیر PATH را در External Web Tools ویژوال استودیو به ابتدای لیست آن منتقل کرده‌اید تا همواره از آخرین نگارش npm نصب شده‌ی در سیستم، استفاده شود.
پس از آن همانند نیوگت که از فایل xml ایی به نام packages.config برای ثبت آخرین تغییرات خودش استفاده می‌کند، npm نیز از فایلی به نام package.json برای ذکر وابستگی‌های مورد نیاز پروژه بهره می‌برد. برای افزودن آن، از منوی Project گزینه‌ی Add new item را انتخاب کرده و سپس npm را در آن جستجو کنید:


در اینجا نام پیش فرض package.json را پذیرفته و این فایل را به پروژه و ریشه‌ی آن اضافه کنید.
اگر گزینه‌ی فوق را در لیست Add new item مشاهده نمی‌کنید، مهم نیست. یک فایل متنی را به نام package.json به ریشه‌ی پروژه‌ی جاری اضافه کنید.
در ادامه محتوای این فایل را به نحو ذیل تغییر دهید:
{
    "name": "asp-net-mvc5x-angular2x",
    "version": "1.0.0",
    "author": "DNT",
    "description": "",
    "scripts": {},
    "license": "Apache-2.0",
    "dependencies": {
        "jquery": "2.2.3",
        "angular2": "2.0.0-beta.15",
        "systemjs": "^0.19.26",
        "es6-promise": "^3.1.2",
        "es6-shim": "^0.35.0",
        "reflect-metadata": "0.1.2",
        "rxjs": "5.0.0-beta.2",
        "zone.js": "^0.6.12",
        "bootstrap": "^3.3.6"
    },
    "devDependencies": {
        "typescript": "^1.8.9",
        "typings": "^0.8.1"
    },
    "repository": {
    }
}
این فایل تنظیمات، سبب بارگذاری خودکار وابستگی‌های مورد نیاز AngularJS 2.0 در ویژوال استودیو می‌شود.

چند نکته:
- هر زمانیکه این فایل را ذخیره کنید، بلافاصله کار دریافت این بسته‌ها از اینترنت آغاز خواهد شد. جزئیات آن‌را می‌توان در پنجره‌ی output ویژوال استودیو مشاهده کرد (و حتما این‌کار را جهت دیباگ کار انجام دهید. بسیاری از مشکلات و خطاها، در اینجا لاگ می‌شوند). بنابراین اگر قصد دارید کار همگام سازی تغییرات را انجام دهید، فقط کافی است دکمه‌های ctrl+s یا save را بر روی این فایل اعمال کنید.
- کاری که دکمه‌ی ctrl+s در این فایل انجام می‌دهد، اعمال خودکار دستور npm install بر روی پوشه‌ای است که package.json در آن قرار دارد. بنابراین برای دریافت این بسته‌ها، روش خط فرمان آن، ابتدا وارد شدن به ریشه‌ی پروژه‌ی جاری و سپس صدور دستور npm install است (که نیازی به آن نیست و ویژوال استودیو این‌کار را به صورت خودکار انجام می‌دهد).
- بسته‌های دریافت شده، در پوشه‌ای به نام node_modules در ریشه‌ی پروژه ذخیره می‌شوند:


برای مشاهده‌ی آن‌ها می‌توان بر روی دکمه‌ی show all files در solution explorer کلیک نمائید.

- درون فایل package.json، پشتیبانی کاملی از intellisense وجود دارد. برای مثال اگر علاقمند بودید تا آخرین نگارش AngularJS را مشاهده کنید، پس از خاصیت angular2 در تنظیمات فوق، " را تایپ کنید تا منوی تکمیل کننده‌ای ظاهر شود:


بدیهی است این منو جهت دریافت آخرین اطلاعات، نیاز به اتصال به اینترنت را دارد.

البته همیشه آخرین شماره نگارش AngularJS 2.0 را در این آدرس نیز می‌توانید مشاهده کنید: CHANGELOG.md

- در این فایل شماره نگارش آغاز شده‌ای با ^ مانند "3.1.2^" به این معنا است که اجازه‌ی نصب نگارش‌های جدیدتری از 3.1.2 نیز داده شده‌است.


به روز رسانی کامپایلر TypeScript

نیاز است یکبار مطلب «مبانی TypeScript؛ تنظیمات TypeScript در ویژوال استودیو» را جهت آشنایی با نحوه‌ی به روز رسانی اجزای مرتبط با TypeScript مطالعه کنید.


افزودن فایل tsconfig.json به پروژه

مرحله‌ی بعد شروع به کار با AngularJS و TypeScript، انجام تنظیمات کامپایلر TypeScript است. برای این منظور از منوی پروژه، گزینه‌ی Add new item، عبارت typescript را جستجو کرده و در لیست ظاهر شده، گزینه‌ی TypeScript JSON Configuration File را با نام پیش فرض آن انتخاب کنید:


اگر این گزینه‌ی ویژه را در لیست add new items ندارید، مهم نیست. یک فایل متنی را به نام tsconfig.json به ریشه‌ی پروژه‌ی جاری اضافه کنید.
پس از افزودن فایل tsconfig.json به ریشه‌ی سایت، تنظیمات آن‌را به نحو ذیل تغییر دهید:
{
    "compileOnSave": true,
    "compilerOptions": {
        "target": "es5",
        "module": "system",
        "moduleResolution": "node",
        "noImplicitAny": false,
        "noEmitOnError": true,
        "removeComments": false,
        "sourceMap": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true
    },
    "exclude": [
        "node_modules",
        "wwwroot",
        "typings/main",
        "typings/main.d.ts"
    ]
}
در مورد جزئیات این تنظیمات در سری «مبانی TypeScript» و «تنظیمات کامپایلر TypeScript» بیشتر بحث شده‌است. فایل ویژه‌ی tsconfig.json تنظیمات پیش فرض ویژوال استودیو را جهت کار با TypeScript بازنویسی می‌کند. بنابراین زمانیکه از این فایل استفاده می‌شود، دیگر نیازی نیست به گزینه‌ی مختلف پروژه، جهت تنظیم TypeScript مراجعه کرد.
برای نمونه خاصیت compileOnSave سبب خواهد شد تا پس از ذخیره سازی یک فایل ts، بلافاصله فایل js معادل آْن تولید شود. نوع ماژول‌ها در اینجا به system.js تنظیم شده‌است و خروجی کدهای js آن از نوع ES 5 درنظر گرفته شده‌است. همچنین فعال سازی decorators نیز در اینجا صورت گرفته‌است. از این جهت که AngularJS2 استفاده‌ی گسترده‌ای را از این مفهوم، انجام می‌دهد.
در قسمت excludes به کامپایلر TypeScript اعلام شده‌است تا از یک سری از مسیرها مانند پوشه‌ی node_modules که پیشتر آن‌را تنظیم و دریافت کردیم، صرفنظر کند.


خلاصه‌ی بحث

تا اینجا با نحوه‌ی نصب پیشنیازهای AngularJS 2 و همچنین TypeScript آشنا شدیم. به صورت خلاصه:
- nmp اصلی را از سایت nodejs دریافت و نصب کنید.
- متغیر PATH را در ویژوال استودیو، به ابتدای لیست ابزارهای خارجی وب آن منتقل کنید تا از npm اصلی استفاده کند.
- فایل project.json را با محتوای ذکر شده، به ریشه‌ی پروژه اضافه کنید. سپس یکبار آن‌را save کنید تا وابستگی‌ها را از اینترنت دریافت کند.
- اطمینان حاصل کنید که آخرین کامپایلر TypeScript را نصب کرده‌اید.
- فایل tsconfig.json را با محتوای ذکر شده، به ریشه‌ی پروژه اضافه کنید.
نظرات مطالب
Angular CLI - قسمت پنجم - ساخت و توزیع برنامه
با سلام
لطفا درباره روش کار با System JS و systemjs.config.js بیشتر توضیح بدید.یا رفرنسی برای مطالعه.ممنون
من تمام مراحل Angular CLI انجام دادم فقط مقادیر  داخل تگ app-root  نمایش نمیدهد برنامه بیلد شده  و خطا ندارد.حالا نمیدونم کجای کار رو اشتباه رفتم جلو که نمایش نمیدهد. فقط فایل  bundel که ساخته به layout اضافه کردم

 <script src="~/ngsrc/main.js"></script>
 "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            //"outputPath": "dist/ngsrc",
            //"index": "src/index.html",
            //"main": "src/main.ts",
            "outputPath": "../../wwwroot/ngsrc",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.app.json",
            "aot": false,
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": []
          },

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'ngsrc';
}

 
مطالب
مدیریت همزمانی و طول عمر توالی‌های Reactive extensions در یک برنامه‌ی دسکتاپ
پس از معرفی و مشاهده‌ی نحوه‌ی ایجاد توالی‌ها در Rx، بهتر است با نمونه‌ای از نحوه‌ی استفاده از آن در یک برنامه‌ی WPF آشنا شویم.
بنابراین ابتدا دو بسته‌ی Rx-Main و Rx-WPF را توسط نیوگت، به یک برنامه‌ی جدید WPF اضافه کنید:
 PM> Install-Package Rx-Main
PM> Install-Package Rx-WPF
فرض کنید قصد داریم محتوای یک فایل حجیم را به نحو ذیل خوانده و توسط Rx نمایش دهیم.
        private static IEnumerable<string> readFile(string filename)
        {
            using (TextReader reader = File.OpenText(filename))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    Thread.Sleep(100);
                    yield return line;
                }
            }
        }
در اینجا برای ایجاد یک توالی IEnumerable ، از yield return استفاده شده‌است. همچنین Thread.Sleep آن جهت بررسی قفل شدن رابط کاربری در حین خواندن فایل به عمد قرار گرفته است.
UI برنامه نیز به نحو ذیل است:
<Window x:Class="WpfApplicationRxTests.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="450" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition  Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Button Grid.Row="0" Name="btnGenerateSequence" Click="btnGenerateSequence_Click">Generate sequence</Button>
        <ListBox Grid.Row="1" Name="lstNumbers"  />
        <Button Grid.Row="2" IsEnabled="False" Name="btnStop" Click="btnStop_Click">Stop</Button>
    </Grid>
</Window>
با این کدها
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Threading;
using System.Windows;

namespace WpfApplicationRxTests
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private static IEnumerable<string> readFile(string filename)
        {
            using (TextReader reader = File.OpenText(filename))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    Thread.Sleep(100);
                    yield return line;
                }
            }
        }

        private IDisposable _subscribe;
        private void btnGenerateSequence_Click(object sender, RoutedEventArgs e)
        {
            btnGenerateSequence.IsEnabled = false;
            btnStop.IsEnabled = true;

            var items = new ObservableCollection<string>();
            lstNumbers.ItemsSource = items;
            _subscribe = readFile("test.txt").ToObservable()
                               .SubscribeOn(ThreadPoolScheduler.Instance)
                               .ObserveOn(DispatcherScheduler.Current)
                               .Finally(finallyAction: () =>
                               {
                                   btnGenerateSequence.IsEnabled = true;
                                   btnStop.IsEnabled = false;
                               })
                               .Subscribe(onNext: line =>
                               {
                                   items.Add(line);
                               },
                               onError: ex => { },
                               onCompleted: () =>
                               {
                                   //lstNumbers.ItemsSource = items;
                               });
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            _subscribe.Dispose();
        }
    }
}

توضیحات

حاصل متد readFile را که یک توالی معمولی IEnumerable را ایجاد می‌کند، توسط فراخوانی متد ToObservable، تبدیل به یک خروجی IObservable کرده‌ایم تا بتوانیم هربار که سطری از فایل مدنظر خوانده می‌شود، نسبت به آن واکنش نشان دهیم.
متد SubscribeOn مشخص می‌کند که این توالی Observable باید بر روی چه تردی اجرا شود. در اینجا از ThreadPoolScheduler.Instance استفاده شده‌است تا در حین خواندن فایل، رابط کاربری در حالت هنگ به نظر نرسد و ترد جاری (ترد اصلی برنامه) به صورت خودکار آزاد گردد.
از متد ObserveOn با پارامتر DispatcherScheduler.Current استفاده کرده‌ایم، تا نتیجه‌ی واکنش‌های به خوانده شدن سطرهای یک فایل مفروض، در ترد اصلی برنامه صورت گیرد. در غیر اینصورت امکان کار کردن با عناصر رابط کاربری در یک ترد دیگر وجود نخواهد داشت و برنامه کرش می‌کند.
در قسمت‌های قبل، صرفا متد Subscribe را مشاهده کرده بودید. در اینجا از متد Finally نیز استفاده شده‌است. علت اینجا است که اگر در حین خواندن فایل خطایی رخ دهد، قسمت onError متد Subscribe اجرا شده و دیگر به پارامتر onCompleted آن نخواهیم رسید. اما متد Finally آن همیشه در پایان عملیات اجرا می‌شود.
خروجی حاصل از متد Subscribe، از نوع IDisposable است. Rx به صورت خودکار پس از پردازش آخرین عنصر توالی، این شیء را Dispose می‌کند. اینجا است که callback متد Finally یاد شده فراخوانی خواهد شد. اما اگر در حین خواندن یک فایل طولانی، کاربر علاقمند باشد تا عملیات را متوقف کند، تنها کافی است که به صورت صریح، این شیء را Dispose نماید. به همین جهت است که مشاهده می‌کنید، این خروجی به صورت یک فیلد تعریف شده‌است تا در متد Stop بتوانیم آن‌را در صورت نیاز Dispose کنیم.


مثال فوق را از اینجا نیز می‌توانید دریافت کنید:
WpfApplicationRxTests.zip
  
مطالب
مسیریابی در Angular - قسمت چهارم - پیش واکشی اطلاعات
اگر مثال قسمت قبل را اجرا کرده باشید، حتما شاهد این تجربه‌ی ناخوشایند کاربری بوده‌اید:
با کلیک بر روی لینک منوی نمایش لیست محصولات، ابتدا قاب خالی لیست محصولات نمایش داده می‌شود:


سپس بعد از یک ثانیه، شاهد بارگذاری اطلاعات جدول لیست محصولات خواهید بود. این یک ثانیه تاخیر را نیز به عمد توسط منبع داده درون حافظه‌ای برنامه ایجاد کردیم، تا بتوان شرایط دنیای واقعی را شبیه سازی کرد:
 InMemoryWebApiModule.forRoot(ProductData, { delay: 1000 }),
برای مدیریت یک چنین حالتی، در سیستم مسیریابی Angular، امکان پیش بارگذاری اطلاعات مسیری خاص، پیش از نمایش قالب آن درنظر گرفته شده‌است.


ارسال اطلاعات ثابت به مسیرهای مختلف برنامه

روش‌های متعددی برای ارسال اطلاعات به مسیرهای مختلف برنامه وجود دارند که تعدادی از آن‌ها را مانند پارامترهای اختیاری، پارامترهای اجباری و پارامترهای کوئری، در قسمت قبل بررسی کردیم. روش دیگری را که در اینجا می‌توان بکار برد، استفاده از خاصیت data تعاریف مسیریابی برنامه است:
 { path: 'products', component: ProductListComponent, data: { pageTitle: 'Product List'} },
خاصیت data، برای تعریف اطلاعات ثابتی که در طول عمر برنامه تغییر نمی‌کنند (static data) مفید است و به صورت مجموعه‌ای از key/valueهای دلخواه، قابل تعریف است.
برای خواندن این اطلاعات ثابت می‌توان از شیء route.snapshot سرویس ActivatedRoute استفاده کرد:
 this.pageTitle = this.route.snapshot.data['pageTitle'];
باید درنظر داشت که چون این اطلاعات ثابت است، در اینجا استفاده‌ی از this.route.params که یک Observable است، غیرضروری می‌باشد.


پیش بارگذاری اطلاعات پویای مسیرهای مختلف برنامه

زمانیکه به صفحه‌ی جزئیات یک محصول مراجعه می‌کنیم، ابتدا این کامپوننت آغاز شده و قالب آن نمایش داده می‌شود. سپس در متد ngOnInit آن کار درخواست اطلاعات از سرور و نمایش آن صورت خواهد گرفت. در این بین، چون زمانی بین درخواست اطلاعات از سرور و دریافت آن صرف می‌شود، کاربر ابتدا شاهد قالب خالی کامپوننت، به همراه برچسب‌های مختلف آن خواهد بود که فاقد اطلاعات هستند و پس از مدتی این اطلاعات نمایش داده می‌شوند.
برای حل این مشکل از سرویسی به نام Route Resolver استفاده می‌شود. در این حالت زمانیکه کاربر صفحه‌ی جزئیات یک محصول را درخواست می‌کند، ابتدا مسیریابی آن فعال شده و سپس سرویس Route Resolver اجرا می‌شود که کار آن درخواست اطلاعات از وب سرور است. در این حالت پس از دریافت اطلاعات از سرور، کار فعالسازی کامپوننت صورت می‌گیرد. به این ترتیب قالب کاملا آماده‌ی کامپوننت، به همراه اطلاعات مرتبط با آن، به کاربر نمایش داده خواهد شد.
بدون استفاده‌ی از Route Resolver، کامپوننت کلاس، پس از آغاز آن، اطلاعات را دریافت می‌کند. اما با بکارگیری Route Resolver، این سرویس ویژه‌است که پیش از هر مرحله‌ی دیگری اطلاعات را دریافت می‌کند.

پیاده سازی یک Route Resolver شامل سه مرحله‌است:
الف) ایجاد و ثبت سرویس Route Resolver
ب) معرفی Route Resolver به تنظیمات مسیریابی
ج) خواندن اطلاعات دریافتی توسط Route Resolver به کمک سرویس ActivatedRoute


ایجاد سرویس Route Resolver

یک Route Resolver به صورت یک سرویس جدید ایجاد می‌شود:
> ng g s product/ProductResolver -m product/product.module
installing service
  create src\app\product\product-resolver.service.spec.ts
  create src\app\product\product-resolver.service.ts
  update src\app\product\product.module.ts
پس از ایجاد قالب خالی این سرویس و به روز رسانی خودکار ماژول مرتبط، جهت تکمیل قسمت providers آن (سطر آخر فوق):
 providers: [ProductService, ProductResolverService]

 فایل src\app\product\product-resolver.service.ts را به نحو ذیل تکمیل کنید:
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';

import { ProductService } from './product.service';
import { IProduct } from './iproduct';

@Injectable()
export class ProductResolverService implements Resolve<IProduct>  {

  constructor(private productService: ProductService,
    private router: Router) { }

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<IProduct> {
    let id = route.params['id'];
    if (isNaN(id)) {
      console.log(`Product id was not a number: ${id}`);
      this.router.navigate(['/products']);
      return Observable.of(null);
    }

    return this.productService.getProduct(+id)
      .map(product => {
        if (product) {
          return product;
        }
        console.log(`Product was not found: ${id}`);
        this.router.navigate(['/products']);
        return null;
      })
      .catch(error => {
        console.log(`Retrieval error: ${error}`);
        this.router.navigate(['/products']);
        return Observable.of(null);
      });
  }
}
توضیحات:
مرحله‌ی اول تعریف یک سرویس Route Resolver، پیاده سازی اینترفیس جنریک Resolve است:
 export class ProductResolverService implements Resolve<IProduct>  {
پارامتر جنریک Resolve، نوع اطلاعاتی را که دریافت می‌کند، مشخص خواهد کرد.
این اینترفیس پیاده سازی متد resolve را با امضایی که مشاهده می‌کنید، درخواست می‌کند:
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<IProduct> {
در اینجا ActivatedRouteSnapshot حاوی اطلاعاتی است از مسیریابی فعال شده. برای مثال اطلاعاتی مانند پارامترهای مسیریابی را می‌توان از آن دریافت کرد.
RouterStateSnapshot وضعیت مسیریاب را در این لحظه در اختیار این سرویس قرار می‌دهد.
خروجی این متد یک Observable است؛ از نوع اطلاعاتی که دریافت می‌کند. زمانیکه مسیریابی فعال می‌شود، متد resolve را فراخوانی کرده و منتظر پایان کار Observable آن می‌شود. پس از آن است که کامپوننت این مسیریابی را فعالسازی خواهد کرد.

در پیاده سازی متد resolve، تعدادی اعتبارسنجی اطلاعات را نیز مشاهده می‌کنید. برای مثال اگر id وارد شده، عددی نباشد، در اینجا فرصت خواهیم داشت پیش از فعالسازی کامپوننت نمایش جزئیات یک محصول، کاربر را به صفحه‌ای دیگر هدایت کنیم.

پس از آن نیاز به دریافت اطلاعات محصول درخواست شده، از REST Web API برنامه است. به همین جهت سرویس ProductService را که در قسمت قبل معرفی کردیم، به سازنده‌ی کلاس تزریق کرده‌ایم تا از طریق متد getProduct آن، کار دریافت اطلاعات یک محصول را انجام دهیم.
در اینجا متد getProduct(+id) به همراه عملگر + است تا id دریافتی را به عدد تبدیل کند. سپس بر روی این متد، عملگر map فراخوانی شده‌است. به این ترتیب می‌توان به اطلاعات دریافتی از سرور، پیش از بازگشت آن به فراخوان متد resolve، دسترسی یافت. به این ترتیب در اینجا نیز می‌توان یک سری اعتبارسنجی را انجام داد. برای مثال آیا id دریافتی، متناظر با محصولی در سمت سرور است یا خیر؟
map operator خروجی را به صورت یک observable بازگشت می‌دهد. به همین جهت در اینجا نیازی به ذکر return Observable.of نیست.


معرفی Route Resolver به تنظیمات مسیریابی

بعد از پیاده سازی سرویس Route Resolver، نیاز است آن‌را به تنظیمات مسیریابی برنامه اضافه کنیم. به همین جهت فایل src\app\product\product-routing.module.ts را گشوده و تنظیمات آن‌را به شکل زیر تغییر دهید:
import { ProductResolverService } from './product-resolver.service';

const routes: Routes = [
  { path: 'products', component: ProductListComponent },
  {
    path: 'products/:id', component: ProductDetailComponent,
    resolve: { product: ProductResolverService }
  },
  {
    path: 'products/:id/edit', component: ProductEditComponent,
    resolve: { product: ProductResolverService }
  }
];
در اینجا با استفاده از خاصیت resolve تنظیمات مسیریابی، می‌توان لیستی از Route Resolverها را به صورت key/valueها معرفی کرد. در اینجا key، یک نام دلخواه است و value، ارجاعی را به سرویس Route Resolver تعریف شده دارد.
در اینجا هر تعداد Route Resolver مورد نیاز را می‌توان تعریف کرد. برای مثال اگر مسیریابی خاصی، اطلاعات دیگری را نیز از سرویس خاصی دریافت می‌کند، می‌توان یک جفت کلید/مقدار دیگر را نیز برای آن تعریف کرد. فقط باید دقت داشت که keyها باید منحصربفرد باشند.
به این ترتیب اطمینان حاصل خوهیم کرد که اطلاعات مورد نیاز این مسیریابی‌ها، پیش از فعالسازی کامپوننت آن‌ها، از REST Web API برنامه دریافت می‌شوند.

 
خواندن اطلاعات دریافتی توسط Route Resolver به کمک سرویس ActivatedRoute

پس از تعریف سرویس Route Resolver سفارشی خود و معرفی آن به تنظیمات مسیریابی برنامه، قسمت نهایی این عملیات، خواندن این اطلاعات پیش واکشی شده‌است. به همین جهت فایل src\app\product\product-detail\product-detail.component.ts را گشوده و محتوای آن‌را به نحو ذیل اصلاح کنید:
  constructor(private route: ActivatedRoute) { }

  ngOnInit(): void {
    this.product = this.route.snapshot.data['product'];
  }
- اگر قرار نیست Route Resolver، اطلاعات مدنظر را «مجددا» واکشی کند، می‌توان از شیء route.snapshot برای خواندن اطلاعات Resolver متناظر با این مسیریابی استفاده کرد. در اینجا خاصیت data‌، به کلید خاصیت resolve تعریف شده‌ی در تنظیمات مسیریابی برنامه اشاره می‌کند که همان product است.
- همانطور که مشاهده می‌کنید، دیگر در این کامپوننت نیازی به تزریق سرویس ProductService نبوده و قسمت دریافت اطلاعات آن از طریق این سرویس، حذف شده‌است.

برای آزمایش آن، لیست محصولات را مشاهده کرده و سپس بر روی لینک مشاهده‌ی جزئیات یک محصول کلیک کنید. البته در اینجا چون هنوز Route Resolver ایی را برای پیش دریافت لیست محصولات ایجاد نکرده‌ایم، ابتدا قاب خالی لیست محصولات نمایش داده می‌شود و سپس لیست محصولات. اما دیگر صفحه‌ی نمایش جزئیات یک محصول، این چنین نیست. ابتدا یک وقفه‌ی یک ثانیه‌ای را حس خواهید کرد و سپس صفحه‌ی کامل جزئیات یک محصول نمایان می‌شود.

یک نکته: اگر یک سرویس Route Resolver، در دو کامپوننت مختلف استفاده شود، اطلاعات آن، بین این دو کامپوننت به اشتراک گذاشته خواهد شد.

مرحله‌ی بعد، ویرایش فایل src\app\product\product-edit\product-edit.component.ts است تا کامپوننت ویرایش جزئیات اطلاعات نیز بتواند از قابلیت پیش واکشی اطلاعات استفاده کند. در اینجا هنوز نیاز به سرویس ProductService است تا بتوان اطلاعات را ذخیره و یا حذف کرد. تنها قسمتی که باید تغییر کند، حذف متد getProduct و تغییر متد ngOnInit است:
ngOnInit(): void {
        this.route.data.subscribe(data => {
            this.onProductRetrieved(data['product']);
        });
    }
در اینجا نیز همانند قسمت قبل، نباید از خاصیت route.snapshot.data استفاده کرد؛ زیرا در حالت مشاهده‌ی جزئیات یک محصول و سپس بر روی لینک افزودن یک محصول جدید، چون root URL Segment تغییر نمی‌کند (یا همان قسمت /products/ در URL جاری)، سبب فراخوانی مجدد متد ngOnInit نخواهد شد. به همین جهت به یک Observable برای گوش فرادادن به تغییرات مسیریابی نیاز است و در اینجا route.data نیز یک Observable است.


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: angular-routing-lab-03.zip
برای اجرای آن فرض بر این است که پیشتر Angular CLI را نصب کرده‌اید. سپس از طریق خط فرمان به ریشه‌ی پروژه وارد شده و دستور npm install را صادر کنید تا وابستگی‌های آن دریافت و نصب شوند. در آخر با اجرای دستور ng serve -o برنامه ساخته شده و در مرورگر پیش فرض سیستم نمایش داده خواهد شد.
نظرات مطالب
Blazor 5x - قسمت 34 - توزیع برنامه‌های Blazor بر روی IIS
یک نکته: base href حساس به بزرگی و کوچکی حروف است!
بین تنظیم
<base href="/blazor/" />
و تنظیم زیر
<base href="/Blazor/" />
تفاوت وجود دارد. یعنی اگر اولی تنظیم شده باشد و کاربر در مرورگر http://localhost/Blazor را وارد کند، با پیام خطای زیر مواجه می‌شود:
System.ArgumentException: The URI is not contained by the base URI
فعلا برای رفع این مشکل می‌توان قطعه کد زیر را پیش از تگ js مربوط به blazor قرار داد تا base href را به صورت پویا تنظیم کند:
<script>
  var path = window.location.pathname.split('/');
  var baseTag = document.getElementsByTagName('base');
  baseTag[0].setAttribute('href', '/' + path[1] + '/');
</script>
اطلاعات بیشتر
نظرات مطالب
Blazor 5x - قسمت 14 - کار با فرم‌ها - بخش 2 - تعریف فرم‌ها و اعتبارسنجی آن‌ها
یک نکته‌ی تکمیلی: روش اعتبارسنجی مقایسه‌ی مقدار دو ورودی
در برنامه‌های Blazor بهتر است از ویژگی جدید [CompareProperty] بجای [Compare] استفاده شود که جزئی از بسته‌ی Microsoft.AspNetCore.Components.DataAnnotations.Validation است. (این مورد در Blazor 5x جزئی از همان ویژگی Compare اصلی شده و دیگر به آن نیازی نیست )
public class EditEmployeeModel 
{
    public string Email { get; set; }

    [CompareProperty("Email", 
        ErrorMessage = "Email and Confirm Email must match")]
    public string ConfirmEmail { get; set; }
}
مطالب
رشته‌ها در ES 6

در بیشتر زبان‌های برنامه‌نویسی قابلیتی تحت عنوان String Interpolation وجود دارد. منظور، فرآیند جایگزین کردن مقادیر، با یکسری placeholder درون یک رشته است. در نسخه‌های قبلی جاوا اسکریپت محدودیت‌هایی در استفاده از رشته‌ها وجود داشت و امکان انجام این کار به صورت توکار مهیا نبود. یعنی برای پیاده‌سازی این قابلیت می‌توانستیم با تغییر prototype شیء String و یا روش‌های دیگری این‌حالت را پیاده‌سازی کنیم (+):

// First, checks if it isn't implemented yet.
if (!String.prototype.format) {
  String.prototype.format = function() {
    var args = arguments;
    return this.replace(/{(\d+)}/g, function(match, number) { 
      return typeof args[number] != 'undefined'
        ? args[number]
        : match
      ;
    });
  };
}
"Hello, {0}, I'm a simple {1}, Today is: {2}".format("World", "String", new Date());

// Output

"Hello, World, I'm a simple String, Today is: Tue Dec 29 2015 10:21:10 GMT+0330 (Iran Standard Time)"

اما در ES 6 با کمک قابلیتی تحت عنوان template string این محدودیت‌ها به طور قابل ملاحظه‌ایی کاهش پیدا کرده است. در واقع یک template string، یک رشته‌ی جاوا اسکریپتی است که به جای (" ") و یا (' ') درون دو کاراکتر (` `) یا به اصطلاح back-tick character محصور خواهد شد. این ویژگی در سناریوهای مختلفی کاریرد دارد. از این ویژگی می‌توانیم جهت الحاق رشته‌ها استفاده کنیم. به عنوان مثال می‌توانیم کد زیر را:

let category = "music";
let id = 2112;

let url = "http://apiserver/" + category + "/" + id;

با کمک template string به اینصورت بازنویسی کنیم:

let category = "music";
let id = 2112;

let url = `http://apiserver/${category}/${id}`;

و یا می‌توانیم مثال ابتدای مطلب را به اینصورت بازنویسی کنیم:

console.log(`Hello, ${"World"}, I'm a simple ${"String"}, Today is: ${new Date()}`);

همانطور که عنوان شد برای استفاده از این قابلیت باید رشته‌ی موردنظر را درون دو کاراکتر (` `) قرار دهیم. سپس درون این کاراکترها می‌توانیم literal text و همچنین یکسری placeholder جهت جایگزین کردن با مقادیر و عبارات موردنظر داشته باشیم. این placeholder‌ها نیز با استفاده از سینتکس { }$ قابل تعریف هستند.  لازم به ذکر است که عبارت موردنظرمان را باید درون دو علامت { } بنویسیم. مقادیر درون این دو علامت می‌توانند هر عبارت معتبر جاوا اسکریپتی باشند: 

let a = 5;
let b = 10;
console.log(`Fifteen is ${a + b} and\nnot ${2 * a + b}.`);
// "Fifteen is 15 and
// not 20."

در کد فوق متغیرهای a و b درون placeholder‌های مربوطه جایگزین خواهند شد. همانطور که مشاهده می‌کنید، این سینتکس نسبت به سینتکس + که برای الحاق رشته‌ها قبلاً مورد استفاده قرار می‌گرفت خیلی بهتر و خواناتر است.

به صورت خلاصه:

  • کد درون placeholder می‌تواند هر عبارت جاوا اسکریپتی باشد.
  • اگر مقدار درون placeholder یک رشته نباشد٬ توسط متد toString به رشته تبدیل خواهد شد.
  • اگر بخواهید درون template string از یک کاراکتر backtick استفاده کنید٬ می‌توانید به این صورت عمل کنید: 
`\``

// یا

"`"
در واقع می‌توانید توسط یک بک‌اسلش ار کارکترهای back tick و $ صرفنظر کنید.

  Multiline Strings 

console.log(`string text line 1
string text line 2`);
// "string text line 1
// string text line 2"

همانطور که مشاهده می‌کنید، template string از متن‌های چندخطی نیز به خوبی پشتیبانی می‌کند. به عنوان مثال اگر رشته‌ی فوق را درون گیومه می‌نوشتیم می‌بایستی از سینتکس + برای الحاق دو خط فوق استفاده می‌کردیم:

console.log("string text line 1\n"+
"string text line 2");
// "string text line 1
// string text line 2"

محدودیت‌های template strings
  • به صورت خودکار کارکترهای خاص را برای شما escape نمی‌کند (جهت جلوگیری از آسیب‌پذیری‌های XSS).
  • به صورت کامل از کتابخانه‌هایی جهت اعمال internationalization پشتیبانی نمی‌کند.
  • جایگزینی برای کتابخانه‌هایی مانند  Mustache و  Nunjucks نیست.
ES 6 قابلیت دیگری تحت عنوان tagged templates جهت رفع محدودیت‌های فوق در اختیارمان قرار می‌دهد. سینتکس آن نیز خیلی ساده است. کافی است قبل از کارکتر back-tick یک tag نوشته شود. قبل از توضیح این قابلیت مثال زیر را در نظر بگیرید:
var x = 1;
var y = 3;
var result = upper `${x} + ${y} is ${x+y}`;

console.log(result);

// Output
// 1 + 3 IS 4
همانطور که مشاهده می‌کنید متغیرهای x و y و همچنین مجموع آنها را درون رشته‌ی فوق قرار داده‌ایم. اما نکته‌ایی که در اینجا وجود دارد این است که مقدار خروجی دقیقاً معادل template نیست؛ زیرا در خروجی، is به صورت حروف بزرگ نمایش داده شده است. دلیل آن نیز این است که قبل از شروع کاراکتر back-tick، از یک تگ با نام upper استفاده کرده‌ایم. در واقع یک تگ چیزی بیشتر از یک تابع نیست که در ادامه پیاده‌سازی آن را مشاهده خواهید کرد:
let upper = function(strings, ...values){
  let result = "";
  for(var i = 0; i < strings.length; i++){
    result += strings[i];
    if(i < values.length){
      result += values[i];
    }
  }
  return result.toUpperCase();
};
تابع فوق دو پارامتر را از ورودی دریافت خواهد کرد: به اولین پارامتر parsed template string گفته می‌شود و مقدار آن متن parse شده درون کاراکتر‌های back-tick است. به پارامتر دوم نیز rest parameter گفته می‌شود که در واقع یک آرایه از مقادیر placeholder هایمان است. در نتیجه مقادیر این دو پارامتر به صورت زیر خواهد بود:
strings = ["", " + ", " is ", ""];
values  = [1, 3, 4];
درون تابع با مقادیر فوق می‌توانیم کارهای مختلفی را انجام دهیم. به عنوان مثال در اینجا ایجاد همان رشته؛ اما اینبار به صورت upper case.
در نتیجه با استفاده از این قابلیت می‌توانیم تگ‌های سفارشی زیادی را ایجاد کنیم. به عنوان مثال می‌توانیم تگی را ایجاد کنیم که تمپلیتی را دریافت کرده و آن را به HTML encoded تبدیل کند و در این‌حالت به ما در جلوگیری از حملات XSS و همچنین رفع محدویت‌هایی که در template strings داشتیم کمک خواهد کرد.

یک مثال عملی
می‌خواهیم یک tag template ایجاد کنیم که به انتهای اعداد درون یک تملپت، مقدار "تومان" را اضافه کرده و خود عدد را نیز به صورت سه رقم سه رقم جدا کند. می‌خواهیم رشته‌ی زیر همراه با مقادیر آن:
var name = "سیروان عفیفی";
var price = 150000;
var text = withToman `${name} با تشکر از خرید شما, مبلغ قابل پرداخت: ${price}`;
alert(text);
در خروجی اینچنین نمایش داده شود:

کدهای تگ withToman نیز به اینصورت میباشد:
function withToman(strings, ...values) {
  return strings.reduce( function (s, v, idx) {
    if(idx > 0) {
      if(typeof values[idx - 1] == "number") {
        s += `${values[idx - 1].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")} تومان`
      }
      else {
        s += values[idx -1];
      }
    }
    return s + v;
  }, "");
}
همچنین در حالت پیشرفته‌تری می‌توان از این قابلیت جهت ایجاد یک DSL یا (Domain Specific Languages) ایده گرفت.
مطالب
فایل آپلود در AngularJs
در این بخش قصد داریم تا به چگونگی آپلود فایل در AngularJs بپردازیم. پلاگین‌های فراوانی جهت آپلود فایل وجود دارند، از جمله ng-file-Upload ، angular-file-upload و jquery-file-upload. البته نمونه‌ی ذکر شده‌ی آخر، یکی از پلاگین‌های معروف JQuery است که با AngularJs هم سازگار شده است.
ما قصد داریم تا در این مجموعه از ng-file-upload که توسط Danial Farid  توسعه داده شده است، استفاده نماییم. این پلاگین شامل یک دایرکتیو کم حجم برای مدیریت آپلود فایل سمت کلاینت است و با تمامی تکنولوژی‌های سمت سرور سازگار می‌باشد. صفحه‌ی دمو پلاگین، شامل برخی از امکانات ذکر شده می‌باشد که قرار است به توسعه و بحث پیرامون آن بپردازیم. این مجموعه دارای اسناد معتبری است که می‌توانید از آن برای توسعه‌ی هر گونه آپلود فایل استفاده نمایید. نسخه‌ی فعلی، نسخه‌ی منتشر شده‌ی 3.0 است. نسخه‌های قبلی این پلاگین نیز در سایت GitHub موجود است.

ویژگی ها

در بخش زیر ویژگی‌های این افزونه که در اسناد آن نیز موجود است، شرح داده شده است:
  • امکان ایجاد progress bar و همچنین قابلیت لغو آپلود.
  • Drag & Drop
  • امکان paste کردن از Clipboard و قابلیت drag & drop از browser
  • امکان resize کردن تصویر قبل از آپلود شدن
  • امکان تغییر دادن orientation تصویر پیش از ارسال
  • قابلیت resume و pause/play در آپلود
  • امکان فیلتر کردن type، size و طول و عرض تصاویر
  • قابلیت تبدیل به Flash shim در صورت عدم پشتیبانی html5 توسط مرورگر

نصب و پیاده سازی

برای استفاده‌ی از پلاگین file upload لازم است که دو مجموعه‌ی زیر را توسط Nuget یا Bower دریافت نمایید. پلاگین اول مربوط به مرورگرهایی است که از html5 پشتیبانی نمی‌کنند.
bower install ng-file-upload-shim --save
bower install ng-file-upload --save
پس از اینکه دو کامپوننت فوق را نصب نمودید، دو فایل اسکریپت دریافت شده را به فایل main html اضافه نمایید. پس آن شروع به نوشتن یک مثال ساده می‌کنیم.
این مثال در JSFIDDLE قرار داده شده است، به این صورت که در این مثال یک فایل آپلود ساده در قالب یک فرم به سرور ارسال می‌گردد. امکانات خیلی ساده نظیر نمایش فایل، پیش از آپلود نیز در این قسمت قرار داده شده است.
به عنوان اولین گام به کد زیر توجه کنید:
<input type="file" ngf-select ng-model="picFile" name="file" accept="image/*" ngf-max-size="2MB" required>
تکه کد فوق مربوط به تگ آپلود فایل است که به توضیح آن خواهیم پرداخت. ngf-select Attribute دایرکتیوی برای تبدیل فایل آپلود، به ng-file-upload است. شما به طور کلی به دو صورت قادر هستید که این کار را انجام دهید. مورد اول ngf-select بود و مورد بعدی ngf-drop است. ngf-drop به گونه‌ای دیگر نوشته می‌شود و کد زیر یک مورد استفاده‌ی از ngf-drop می‌باشد.
<div ngf-drop ng-model="picFile" ngf-pattern="image/*">
     ...
</div>
همانطور که ملاحظه می‌کنید در این نوع فراخوانی، یک تگ div به یک file select مبدل شده که در مورد آن صحبت خواهیم نمود. همانطور که مشاهده می‌کنید، شما قادرید تا با استفاده از Attribute ایی با نام accept، فایل‌های ارسالی را از لحاظ محتوایی فیلتر کنید. در کد فوق image/* این مفهوم را می‌رساند که شما قادرید فایل‌های تصویری و با هر فرمتی را به سرور ارسال نمایید. اما اگر آن را به صورت image/jpg بنویسیم این عملیات تنها به تصاویر با فرمت jpeg منتهی می‌شود. مورد بعدی محدودیت حجمی تصویر است. شما با ngf-max-size و مقداری که درون آن قرار می‌دهید، قادرید تا محدودیت حجمی را بر روی فایل‌های ارسالی به سرور اعمال نمایید. اگر با نوشتار form validationها در Angular آشنا باشید، به سادگی قادرید تا خطاهایی را که کاربر ممکن است در حین آپلود انجام دهد، به او گوشزد کنید. به کد زیر توجه کنید:
<i ng-show="myForm.file.$error.required">*required</i><br>
<i ng-show="myForm.file.$error.maxSize">
File too large: max is 2M
</i>
همانطور که مشاهده می‌کنید syntax نمایش خطاها دقیقا مانند نمایش خطاها در validation فرم‌های انگیولاری است.
و اما اینکه چه کارهایی نیاز است تا در سمت Controller انجام دهیم. اول اینکه لازم است شما dependency ngFileUpload زیر را به app.module اضافه نمایید. حال اینکه پس از inject کردن این وابستگی، تنها کافیست که وابستگی Upload را به کنترلر تزریق نمایید. این وابستگی وظیفه‌ی ارسال فایل به سرور را بر عهده دارد. به مثال زیر توجه نمایید:
app.controller('MyCtrl', ['$scope', 'Upload', '$timeout', function ($scope, Upload, $timeout) {
    // the method uploadPic called from Angular View
$scope.uploadPic = function(file) {
    file.upload = Upload.upload({
      url: 'https://angular-file-upload-cors-srv.appspot.com/upload',
      data: {file: file, otherData: $scope.otherData},
    });

    file.upload.then(function (response) {
// waiting for response
        $timeout(function () {
file.result = response.data;
        });
    }, function (response) {
//error
        if (response.status > 0)
$scope.errorMsg = response.status + ': ' + response.data;
    }, function (evt) {
//progress
        file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
console.log(file.progress);
    });
    }
}]);
تمام عملیات در قالب یک فراخواننده‌ی ng-click از سوی view آغاز شده‌است. با این رخداد، متد uploadPic که همراه آن فایل attach شده نیز به عنوان پارامتر ارسال می‌گردد، فرخوانی می‌شود و کلیه‌ی کارها طی عملیات post، توسط وابستگی Upload برای سرور ارسال می‌گردد. همانند http$ درون بلاک then سه متد Success ، Error و progress پیاده‌سازی شده است. البته اگر به فرایند مقداردهی Url و data توجه کنید می‌بینید که فایل‌ها نیز درون data قرار گرفته‌اند. شما برای ارسال فایل‌ها می‌توانید از وابستگی upload$ نیز استفاده کنید که مثالی هم در این زمینه در mono-software.com پیاده‌سازی شده است که از ng-file-upload و در سمت سرور، از ASP.NET Web API استفاده می‌کند. در این مثال چندین فایل به صورت غیر همزمان برای سرور ارسال می‌گردند.
توحه داشته باشید که شما برای uploadهای ساده، قادر هستید تا دایرکتیو خاص خود را نوشته و از آن استفاده نمایید. در msdn نمونه‌ای از این کار، یعنی نوشتن دایرکتیو فایل آپلود، به طور کامل پیاده‌سازی شده است. اما مزیت ng-file-upload این است که این پلاگین، با بسیاری از پلاگین‌های 3rd party دیگر مانند ng-image-crop به خوبی همگام شده‌است. مثالی از آن را می‌توانید در اینجا مشاهده نمایید.
در این مقاله، هدف کلی، چگونگی فایل آپلود در AngularJs و پس از آن معرفی و بررسی ویژگی‌ها و همچنین تشریح عملکرد ng-file-upload بود. این افزونه قابلیت‌های فراوان دیگری نیز دارد که بنابر نیاز می‌توانید در کد‌های خود از آن‌ها استفاده نمایید.
مطالب
آموزش (jQuery) جی کوئری 7#
پس از انواع روش‌های انتخاب عناصر در jQuery اکنون زمان آشنایی با متدها و توابعی جهت پردازش مجموعه انتخاب شده رسیده است.
٢-٣- مدیریت مجموعه انتخاب شده
هز زمان که مجموعه ای از عناصر انتخاب انتخاب می‌شوند، خواه این عناصر از طریق انتخاب کننده‌ها انتخاب شده باشند و یا تابع ()$ در صدد ایجاد آن باشد، مجموعه ای در اختیار داریم که آماده دستکاری و اعمال تغییر با استفاده از متدهای jQuery می‌باشد. این متدها را در پست‌های آتی بررسی خواهیم کرد. اما اکنون به این نکته می‌پردازیم که اگر بخواهیم از همین مجموعه انتخاب شده زیر مجموعه ای ایجاد کنیم و یا حتی آن را گسترش دهیم، چه باید کرد؟ به طور کلی در این پست پیرامون این مورد بحث خواهد شد که چگونه می‌توانیم مجموعه انتخاب شده را به آن صورت که می‌خواهیم بهیود دهیم.
برای درک مطالبی که قصد توضیح آنها را در این قسمت داریم، یک صفحه کارگاهی دیگر نیز در فایل قابل دانلود این کتاب موجود می‌باشد که با نام chapter2/lab.wrapped.set.html قابل دسترسی می‌باشد. نکته مهم در مورد این صفحه کارگاهی آن است که می‌بایست عبارات و دستورهای کامل را با ساختار صحیح وارد کنیم در غیر این اینصورت این صفحه کاربردی نخواهد داشت.


٢-٣-١-تعیین اندازه یک مجموعه عناصر
قبلا اشاره کردیم که مجموعه عناصر jQuery شباهت هایی با آرایه دارد. یکی از این شباهت‌ها داشتن ویژگی length می‌باشد که مانند آراه در جاوااسکریپت ، تعداد عناصر موجود در مجموعه را شامل می‌شود.
افزون بر این ویژگی، jQueryیک متد را نیز معرفی کرده است که دقیقا شبیه به length عمل می‌کند. این متد ()size می‌باشد که استفاده از آن را در مثال زیر مشاهده می‌کنید.
$('#someDiv')
       .html('There are '+$('a').size()+' link(s) on this page.');
این مثال تمام لینک‌های موجود در صفحه را شناسایی می‌کند و سپس بااستفاده از متد ()size تعداد آنها را بر می‌گرداند. در واقع یک رشته ایجاد می‌شود و در یک عنصر با شناسه someDiv قرار داده می‌شود. متد html در پست‌های آتی بررسی می‌شود. فرم کلی متد ()size را در زیر مشاهده می‌کنید.
()size
تعداد عناصر موجود در مجموعه را محاسبه می‌کند
پارامترها
بدون پارامتر
خروجی
تعداد عناصر مجموعه
اکنون که تعداد عناصر مجموعه را می‌دانیم چگونه می‌توانیم به هریک از آنها دسترسی مستقیم داشته باشیم؟

٢-٣-٢-بکارگیری عنصرهای مجموعه
به طور معمول پس از انتخاب یک مجموعه با استفاده از متدهای jQuery، عملی را بروی آن عناصر انتخاب شده انجام می‌دهیم، مانند مخفی کردن آنها با متد ()hide، اما گاهی اوقات می‌خواهیم بروی یک یا چند مورد خاص از عناصر انتخاب شده عملی را اعمال کنیم. jQuery چند روش مختلف را به منظور اینکار ارایه می‌دهد.

از آنجا که مجموعه عناصر انتخاب شده در jQuery مانند آرایه در جاوااسکریپت می‌باشد، بنابراین به سادگی می‌توانیم از اندیس برای دستیابی به عناصر مختلف مجموعه استفاده کنیم. برای مثال به منظور دسترسی به اولین عکس از مجموعه عکس‌های انتخاب شده که دارای صفت alt می‌باشند از دستور زیر استفاده می‌کنیم:
$('img[alt]')[0]
اما اگر ترجیح می‌دهید به جای اندیس از یک متد استفاده کنید، jQuery متد ()get را در نظر گرفته است:
(get(index
برای واکشی یک یا تمام عناصر موجود در مجموعه استفاده می‌شود. اگر برای این متد پارامتری ارسال نشود، تمام عناصر را در قالب یک آرایه جاوااسکریپت بر می‌گرداند، اما در صورت ارسال یک پارامتر، تنها آن عنصر را بر می‌گرداند.
پارامتر
شماره اندیس یک عنصر که می‌بایست یک مقدار عددی باشد.
خروجی
یک یا آرایه ای از عناصر
دستور زیر مانند دستور قبلی عمل می‌کند:
$('img[alt]').get(0)
متد ()get می‌تواند برای بدست آوردن یک ارایه از عناصر پیچیده نیز استفاده شود. مثلا:
var allLabeledButtons = $('label+button').get();
خروجی دستور بالا لیست تمام button‌های موجود در صفحه است که بعد از عنصر label قرار گرفته اند، در نهایت این آرایه در متغیری به نام allLabeledButtons قرار خواهد گرفت.

در متد ()get دیدیم که با دریافت شماره اندیس یک عنصر، آن عنصر را برای ما برمی گرداند، عکس این عمل نیز امکان پذیر می‌باشد. فرض کنید می‌خواهیم از میان تمام عناصر عکس، شماره اندیس عکسی با شناسه findMe را بدست آوریم. برای این منظور می‌توانیم از کد زیر بهره ببریم:

var n = $('img').index($('img#findMe')[0]);
فرم کلی متد ()index به صورت زیر است:
(index(element
عنصر ارسالی را در مجموعه عناصر پیدا می‌کند، سپس شماره اندیس ان را بر می‌گرداند. اگر چنین عنصری در مجموعه یافت نشد خروجی 1- خواهد بود.
پارامتر
پارامتر این متد می‌تواند یک عنصر و یا یک انتخاب کننده باشد که خروجی انتخاب کننده نیز در نهایت یک عنصر خواهد بود.
خروجی
شماره اندیس عنصر در مجموعه

٢-٣-٣-برش و کوچک کردن مجموعه ها
ممکن است شرایطی پیش آید که پس از بدست آوردن یک مجموعه عناصر انتخاب شده نیاز باشد که عنصری به آن مجموعه اضافه و یا حتی عنصری را از آن حذف کنیم تا در نهایت مجموعه ای باب میل ما بدست آید. برای انجام چنین تغییرهایی در یک مجموعه jQuery کلکسیون بزرگی از متدها را برای ما به همراه دارد. اولین موردی که به آن می‌پردازیم، افزودن یک عنصر به مجموعه می‌باشد.

اضافه کردن عناصر بیشتر به یک مجموعه عنصر انتخاب شده
همواره ممکن است شرایطی پیش آید که پس از ایجاد یک مجموعه عناصر انتخاب شده، بخواهیم عنصری را به آن اضافه کنیم. یکی از دلایلی که باعث می‌شود این امر در jQuery بیشتر مورد نیاز باشد توانایی استفاده از متدهای زنجیره ای در jQuery است.
ابتدا یک مثال ساده را بررسی می‌کنیم. فرض کنید می‌خواهیم تمام عناصر عکس که دارای یکی از دو خصوصیت alt و یا title می‌باشند را انتخاب کنیم، با استفاده از انتخاب کننده‌های قدرتمند jQuery دستوری مانند زیر خواهیم نوشت:
$('img[alt],img[title]')
اما برای آنکه با متد ()add که به منظور افزودن عنصر به مجموعه عناصر می‌باشد آشنا شوید این مثال را به صورت زیر می‌نویسیم:
$('img[alt]').add('img[title]')
استفاده از متد ()add به این شکل موجب می‌شود تا بتوانیم مجموعه‌های مختلف را به یکدیگر متصل کنیم و یک مجموعه کلی‌تر از عناصر انتخاب شده ایجاد کنیم. متد ()add در این حالت مانند متد ()end عمل می‌کند که در قسمت ٢-٣-٦شرح داده خواهد شد.
ساختار کلی متد ()add به صورت زیر است:
َ(add(expression
ابتدا یک کپی از مجموعه انتخاب شده ایجاد می‌کند، سپس با افزودن محتویات پارامتر expression به آن نمونه، یک مجموعه جدید تشکیل می‌دهد. پارامتر expression می‌تواند حاوی یک انتخاب کننده، قطعه کد HTML، یک عنصر و یا آرایه ای از عناصر باشد.
پارامتر
در این پارامتر مواردی (مانند رشته، آرایه، المان) که می‌خواهیم به مجموعه عناصر انتخاب شده اضافه شوند قرار می‌گیرد. که می‌تواند انتخاب کننده، قطعه کد HTML، یک عنصر و یا ارایه ای از عناصر باشد.
خروجی
یک کپی از مجموعه اصلی به علاوه موارد اضافه شده.
اصلاح عناصر یک مجموعه عنصر انتخاب شده
در قسمت قبل دیدیم که چگونه با استفاده از متد ()add و با بکار گیری آن در توابع زنجیره ای، توانستیم عناصری جدید به مجموعه انتخاب شده اضافه کنیم. عکس این عمل را نیز می‌توان با ستفاده از متد ()not در توابع زنجیره ای انجام داد. این متد عملکرید شبیه به فیلتر not: دارد، اما با این تفاوت که بکار گیری آن مانند متد ()add می‌باشد و می‌توان در هر جایی از زنجیره از آن استفاده کرد تا عناصر مورد نظر را از مجموعه انتخاب شده حذف کنیم.
فرض کنید می‌خواهیم تمامی عناصر عکسی را که دارای خصوصیت title می‌باشند به استثنای آن موردی که واژه puppy در مقدار مربوط به این صفت استفاده کرده اند را انتخاب کنیم. این کار به سادگی و با استفاده از دستوری مانند([ "img[title]:not([title*="puppy می‌توان انجام داد. اما برای آن که مثالی از چگونگی کار متد ()not ببینید، این کار را به شکل زیر انجام می‌دهیم:
$('img[title]').not('[title*=puppy]')
این دستور تمام عکس‌های دارای خصوصیت title را به استثنا titleهایی که مقدار puppy در آنها وجود دارد را انتخاب می‌کند.
شکل کلی متد ()not مانند زیر است:
(not(expression
ابتدا یک کپی از مجموعه انتخاب شده ایجاد می‌کند، سپس از آن کپی عناصری را که expression مشخص می‌کند را حذف می‌نماید.
پارامتر
این پارامتر تعیین کننده عناصر در نظر گرفته شده برای حذف می‌باشد. این پارامتر می‌تواند یک عنصر، ارایه ای از عناصر، انتخاب کننده و یا یک تابع باشد.
اگر این پارامتر تابع باشد، تک تک عناصر مجموعه به آن ارسال می‌شوند و هر یک که خروجی تابع را برابر با مقدار true کند، حذف می‌شود.
خروجی
یک کپی از مجموعه اصلی بدون موارد حذف شده. 
این شیوه برای ایجاد مجموعه هایی که انتخاب کننده‌ها قادر به ساخت آن‌ها نمی‌باشند، کاربرد بسیار مناسبی دارد، زیرا از تکنیک‌های برنامه نویسی استفاده می‌کند و دست ما را برای اعمال انتخاب‌های گوناگون باز می‌کند.
اگر در شرایطی خاص با حالتی روبرو شدید که احساس کردید عکس این انتخاب برای شما کارایی دارد، باز می‌توانید از یکی دیگر از متدهای jQuery استفاده کنید، متد ()filter عملکردی مشابه با متد ()not دارد با این تفاوت که عناصری از مجموعه حذف می‌شوند که خروجی تابع را false کنند.
فرض کنید می‌خواهیم تمام عناصر td که دارای یک عنصر عددی می‌باشند را انتخاب کنیم. با وجود قدرت فوق العاده انتخاب کننده‌های jQuery به ما ارایه می‌دهند، انجام چنین کاری با استفاده از انتخاب کننده‌ها غیر ممکن است. در این حالت از متد ()filter را به شکل زیر استفاده می‌کنیم:
$('td').filter(function(){return this.innerHTML.match(/^\d+$/)})
دستور فوق یک مجموعه از تمام عناصر td انتخاب می‌کند، سپس تک تک عناصر مجموعه انتخاب شده را به تابعی که پارامتر متد ()filter می‌باشد، ارسال می‌کند. این تابع با استفاده از عبارت منظم مقدار عنصر کنونی را می‌سنجد. اگر این مقدار یک یا زنجیره ای از ارقام بود، خروجی تابع true خواهد بود، و ان عنصر از مجموعه حذف نمی‌شود، اما اگر این مقدار عددی نبود، خروجی تابع false بوده و عنصر از مجموعه کنار گذاشته می‌شود.
شکل کلی متد ()filter به شکل زیر است.
(filter(expression
ابتدا یک کپی از مجموعه انتخاب شده ایجاد می‌کند، سپس از آن کپی عناصری را که expression مشخص می‌کند را حذف می‌نماید.
پارامتر
این پارامتر تعیین کننده عناصر در نظر گرفته شده برای حذف می‌باشد. این پارامتر می‌تواند یک عنصر، ارایه ای از عناصر، انتخاب کننده و یا یک تابع باشد.
اگر این پارامتر تابع باشد، تک تک عناصر مجموعه به آن ارسال می‌شوند و هر یک که خروجی تابع را برابر با مقدار false کند، حذف می‌شود.
خروجی
یک کپی از مجموعه اصلی بدون عناصر حذف شده.  

ایجاد یک زیر مجموعه از مجموعه عناصر انتخاب شده
گاهی اوقات داشتن یک زیر مجموعه از عناصر یک مجموعه، چیزی است که دنبال آن هستیم. برای این منظور jQuery متد ()slice را ارایه می‌کند که عناصر را بر اساس جایگاه آن‌ها به زیر مجموعه هایی کوچکتر تقسیم می‌کند. نتیجه استفاده از این متد یک مجموعه جدید برگرفته از تعدادی عناصر پشت سر هم،از یک مجموعه انتخاب شده خواهد بود:
شکل کلی متد ()slice مانند زیر است:
(slice(begin, end
ایجاد و برگرداندن یک مجموعه جدید از بخشی از عناصر پشت سر هم در یک مجموعه اصلی.
پارامتر
begin: پارامتر begin که یک پارامتر عددی می‌باشد و مقدار اولیه آن از صفر آغاز می‌شود، نشان دهنده اولین عنصری است که می‌خواهیم در مجموعه جدید حضور داشته باشد.
end: پارامتر دوم که آن هم یک پارامتر عددی می‌باشد و از صفر آغاز می‌شود، در این متد اختیاری است. این پارامتر اولین عنصری است که نمی‌خواهیم از آن به بعد در مجموعه جدید حضور داشته باشد را مشخص می‌کند. اگر مقداری برای این پارامتر ننویسیم، به صورت پیش فرض تا انتهای مجموعه انتخاب می‌شود.
خروجی
یک مجموعه عنصر جدید.
 اگر بخواهیم از یک مجموعه کلی، تنها یک عنصر را در قالب یک مجموعه انتخاب کنیم می‌توانیم از متد ()slice استفاده کنیم و مکان آن عنصر در مجموعه را به آن ارسال کنیم. دستور زیر مثالی از این حالت می‌باشد:
$('*').slice(2,3);
این مثال ابتدا تمام عناصر موجود در صفحه را انتخاب می‌کند، سپس سومین عنصر از آن مجموعه را در یک مجموعه جدید باز می‌گرداند. دقت کنید که دستور فوق با دستور (2)get.('*')$ کاملا متفاوت است، چرا که خروجی این دستور تنها یک عنصر است، در حالی که خروجی دستور فوق یک مجموعه است.
از همین رو دستور زیر باعث ایجاد یک مجموعه که شامل چهار عنصر اولیه صفحه می‌باشد، می‌شود.
$('*').slice(0,4);
برای ایجاد یک مجموعه از عناصر انتهایی موجود در صفحه نیز می‌توان از دستوری مانند زیر استفاده کرد:
$('*').slice(4);
این دستور تمام عناصر موجود در صفحه را انتخاب می‌کند، سپس مجموعه ای جدید می‌سازد که تمام عناصر به استثنای چهار عنصر اول را در خود جای می‌دهد.


٢-٣-٤-ایجاد مجموعه بر اساس روابط
jQuery به ما این توانایی را داده است تا مجموعه هایی را انتخاب کنیم، که اساس انتخاب عناصر، رابطه سلسله مراتبی آنها با عناصر HTML صفحه باشد. اکثر این متدها یک پارامتر اختیاری از نوع انتخاب کننده دریافت می‌کنند که می‌تواند برای انتخاب عناصر مجموعه استفاده شود. در صورتی که چنین پارامتری ارسال نگردد، تمام عناصر واجد شرایط متد در مجموعه انتخاب می‌شوند.


جدول ٢-٤-متدهای موجود برای ایجاد مجموعه‌های جدید بر اساس روابط
 توضیح متد
 مجموعه ای را برمی گرداند که شامل تمام فرزندان بدون تکرار از عناصر مجموعه می‌باشد.
() children
 مجموعه ای شامل محتویات تمام عناصر برمی گرداند. (از این متد معمولا برای عناصر iframe استفاده می‌شود)
() contents
 مجموعه ای شامل فرزندان پدرش که بعد از خود این عنصر می‌باشند را برمی گرداند. این مجموعه عنصر تکراری ندارد.
() next
 مجموعه ای شامل تمام فرزندان پدرش که بعد از خود این عنصر می‌باشند را بر می‌گرداند.
() nextAll
 مجموعه ای شامل نزدیک‌ترین پدر اولین عنصر مجموعه را بر می‌گرداند.
() parent
 مجموعه ای شامل تمام پدران مستقیم عناصر مجموعه را بر می‌گرداند. این مجموعه عنصر تکراری ندارد.
() parents
 مجموعه ای شامل فرزندان پدرش که قبل از خود این عنصر می‌باشند را برمی گرداند. این مجموعه عنصر تکراری ندارد. () prev
  مجموعه ای شامل تمام فرزندان پدرش که قبل از خود این عنصر می‌باشند را بر می‌گرداند. () prevAll
 مجموعه ای بدون عنصر تکراری را بر می‌گرداند که شامل تمام فرزندان پدر خود عنصر خواهد بود.
() siblings
تمامی جدول بالا غیر از متد ()contents پارامتری از نوع رشته که انتخاب کننده برای متد می‌باشند، استفاده می‌کند.

٢-٣-٥-استفاده از مجموعه‌های انتخاب شده برای انتخاب عناصر
با وجود اینکه تاکنون با شمار زیادی از توانایی‌های انتخاب و انتخاب کننده‌ها در jQuery آشنا شده اید، هنوز چند مورد دیگر نیز برای افزایش قدرت انتخاب باقی مانده است.
متد ()find بروی یک مجموعه عناصر انتخاب شده به کار گرفته می‌شود و یک پارامتر ورودی نیز دارد. این پارامتر که یک انتخاب کننده است تنها بروی فرزندان این مجموعه اعمال می‌شود. برای مثال فرض کنید یک مجموعه از عناصر انتخاب و در متغیر wrapperSet قرار گرفته است. با دستور زیر می‌توانیم تمام عناصر (تگ) cite را که درون یک تگ p قرار گرفته اند را انتخاب کنیم، به شرطی که آن‌ها فرزندان عناصر مجموعه wrapperSet باشند:
wrappedSet.find('p cite')
البته می‌توانیم این تکه کد را به صورت زیر هم بنویسیم:
$('p cite', wrapperSet)
مانند سایر متدهای معرفی شده قدرت اصلی این متد نیز هنگام استفاده در متدهای زنجیره ای مشخص می‌شود.
شکل کلی متد ()findمانند زیر است:
(find(selector
یک مجموعه عنصر جدید ایجاد می‌کند که شامل فرزندان عناصر مجموعه قبل می‌شود.
پارامتر
یک انتخاب کننده است که در قالب یک رشته به این متد ارسال می‌شود.
خروجی
یک مجموعه عنصر جدید
جهت پیدا کردن عناصری که داخل یک wrapperSet می‌توانیم از متد دیگری به نام ()contains نیز استفاده کنیم. این متد مجموعه ای را بر می‌گرداند که شامل تمام عناصری است که در انتخاب کننده پارامتر ورودی است. مثلا
$('p').contains('Lorem ipsum')
این دستور تمامی عناصر p را که شامل Lorem ipsum است را بر می‌گرداند. قالب کلی متد مانند زیر است:
(contains(text
مجموعه ای از عناصر که شامل متن ورودی می‌باشند را بر می‌گرداند.
پارامتر
رشته ورودی که می‌خواهیم در عنصر فراخوان متد جستجو شود.
خروجی
مجموعه ای از عناصر از نوع فراخوان متد را بر می‌گرداند که شامل متن ورودی باشد.
آخرین متدی که به بررسی آن می‌پردازیم متد ()is می‌باشد. با استفاده از این متد می‌توانیم اطمینان حاصل کنیم که دست کم یک عنصر از مجموعه عناصر، شرایط مشخص شده توسط ما را دارا باشد. یک انتخاب کننده به این متد ارسال می‌شود، اگر عنصری از مجموعه عناصر انتخاب شد، خروجی متد true می‌شود و در غیر این صورت مقدار false بر گردانده خواهد شد. برای مثال:
var hasImage = $('*').is('img');
در صورت وجود دست کم یک عنصر عکس در کل عناصر صفحه، دستور بالا مقدار متغیر hasImage را برابر true قرار می‌دهد.
قالب کلی متد ()is مانند زیر است:
(is(selector
بررسی می‌کند که آیا عنصری در مجموعه وجود دارد که انتخاب کننده ارسالی آن را انتخاب کند؟
پارامتر
یک انتخاب کننده است که در قالب یک رشته به این متد ارسال می‌شود.
خروجی
مقدار true در صورت وجود دست کم یک عنصر و false در صورت عدم وجود توسط تابع برگردانده می‌شود.

٢-٣-٦-مدیریت زنجیره‌های jQuery
تاکنون در مورد استفاده از متدها و توابع زنجیره ای زیاد بحث کرده ایم و انجام چندین عمل در یک دستور را به عنوان یک قابلیت بزرگ معرفی کرده ایم و البته از آن هم استفاده کردیم و در ادامه نیز استفاده خواهیم کرد. به کار گیری متدها به صورت زنجیره ای نه تنها موجب نوشتن کدهای قدرتمند و قوی به صورت مختصر و خلاصه می‌شود، بلکه از لحاظ کارایی نیز نکته مثبتی محسوب می‌شود، زیرا برای اعمال هر متد نیازی به محاسبه و انتخاب مجدد مجموعه نخواهد بود.
بنابراین متدهای مختلفی که در زنجیره استفاده می‌کنیم، برخی از آنها ممکن است مجموعه‌های جدیدی تولید کنند. برای مثال استفاده از متد ()clone موجب می‌شود تا مجموعه ای جدید از کپی عناصر در مجموعه اول ایجاد شود. زمانی که یکی از متدهای زنجیره یک مجموعه جدید را تولید می‌کند، دیگر راهی برای استفاده از مجموعه پیشین در زنجیره نخواهیم داشت و این نکته زنجیره ما را به خطر می‌اندازد. عبارت زیر را در نظر بگیرید:
$('img').clone().appendTo('#somewhere');
این مثال دو مجموعه ایجاد می‌کندو نخست مجموعه ای شامل تمام عناصر عکس صفحه ایجاد می‌شود و مجموعه دوم کپی مجموعه اول است که به انتهای عنصری با شناسه somewhere اضافه می‌شود. حال اگر بخواهیم پس از اعمال کپی بروی مجموعه اصلی عملی مانند افزودن یک کلاس را بروی آن انجام دهیم چه باید بکنیم؟ همچنین نمی‌توانیم مجموعه اصلی را به انتهای زنجیره انتقال دهیم، چون بروی قسمتی دیگر اثر خواهد گذاشت.
برای مرتفع کردن چنین نیازی، jQuery متد ()end را معرفی کرده است. زمانی از این متد استفاده می‌شود،  یک نسخه پشتیبان از مجموعه کنونی ایجاد می‌شود . همان مجموعه برگردانده می‌شود. بنابراین اگر متدی پس از آن ظاهر شودف اثرش بروی مجموعه اولیه خواهد بود. مثال زیر را در نظر بگیرید:
$('img').clone().appendTo('#somewhere').end().addClass('beenCloned');
این مثال دو مجموعه ایجاد می‌کندو نخست مجموعه ای شامل تمام عناصر عکس صفحه ایجاد می‌شود و مجموعه دوم کپی مجموعه اول است که به انتهای عنصری با شناسه somewhere اضافه می‌شود. اما با استفاده از متد ()end  همان مجموعه اولیه در ادامه زنجیره قرار خواهد گرفت و سپس متد ()addClass بروی تمامی عناصر عکس اعمال می‌شود، نه تنها عکس‌های موجود در مجموعه اول، اگر از متد ()end  استفاده نشود متد ()addClass برویعناصر مجموعه دوم اعمال خواهد شد.
قالب کلی متد ()end به شکل زیر است:
()end
در متدهای زنجیره ای استفاده می‌شود و از مجموعه کنونی یک پشتیبان می‌گیرد تا همان مجموعه در زنجیره جریان داشته باشد.
پارامتر
ندارد
خروجی
مجموعه عنصر قبلی
شاید در نظر گرفتن مجموعه‌ها در متدهای زنجیره ای به شکل یک پشته به درک بهتر از متد ()end  کمک کند. هر زمان که یک مجموعه جدید در زنجیره ایجاد می‌شود، آن مجموعه به بالای پشته افزوده می‌شود، اما با فراخوانی متد ()end، بالاترین مجموعه از این پشته برداشته می‌شود و مجدادا مجموعه پیشین در زنجیره قرار می‌گیرد.
متد دیگری که توانایی ایجاد تغییر در این پشته خیالی را دارد، متد ()andSelf می‌باشد. این متد دو مجموعه بالای پشته را با یکدیگر ادغام می‌کند و آن‌ها را به یک مجموعه تبدیل می‌کند.
شکل کلی متد ()andSelf به صورت زیر است:
()andSelf
دو مجموعه پیشین در یک زنجیره را با یکدیگر ادغام می‌کند.
پارامتر
ندارد
خروجی
مجموعه عنصری ادغام شده
در مباحث بعدی کار با صفت‌ها و ویژگی‌های عناصر بحث خواهد شد.

موفق و موید باشید