دوره آموزش AngularJS – مبانی

0005-learn-angularjs-course-beginner-basic-featured-image

دوره آموزش AngularJS – مبانی بخش اول

AngularJS یک فریمورک اپلیکیشن سمت-کاربر است که HTML را بازتعریف می‌کند.

اگر شما یک توسعه‌دهنده‌ی وب باشید، حتما AngularJS را با دیگر فریمورک‌ها و کتابخانه‌های معروف جاوااسکریپت دیگر، همچون jQuery، Knockout، Backbone، Ember و حتی React مقایسه کرده‌اید. بطور مشابه، اگر اطلاعاتی راجع به توسعه رابط کاربری گرافیکی داشته باشید، حتما با الگو‌های MVC، MVVM و یا MVW آشنایی دارید. دانستن این نکات طبیعی می‌باشد، اما می‌تواند درک شما از AngularJS را تحت تاثیر قرار دهد. در نتیجه در این بخش، دوره آموزش AngularJS – مبانی، توصیه می‌شود که به AngularJS تنها به شکل یک فریمورک جاوااسکریپت نگاه کنید. کلیه دانش خود در مورد طراحی رابط گرافیکی، الگو‌های طراحی و دیگر فریمورک‌ها و کتابخانه‌ها را فراموش کنید. به مطالب این بخش نگاه کنید تا متوجه شوید AngularJS چگونه عمل می‌کند. یا بهتر بگویم، آنرا تنها به شکل یک توسعه‌دهنده‌ی HTML ببینید.

در این بخش، سه ساختار اصلی و پایه‌ی AngularJS را فرا‌خواهیم گرفت. عبارات (Expressions)، رهنمود‌ها (Directives) و حوزه‌ها (Scopes). البته قبل از توضیح این سه ساختار اصلی و پایه، به نحوه‌ی اضافه نمودن AngularJS به پروژه‌ها و راه‌اندازی آن می‌پردازیم.

برای عدم ایجاد کج‌فهمی در مفاهیم و عبارات، در این سری از آموز‌ش‌ها از  در کنار ترجمه‌ی اینگونه مفاهیم و عبارات عبارت انگلیسی آنها هم آورده می‌شود.

راه‌اندازی AngularJS

برای دریافت AngularJS می‌توانید به صفحه اصلی این فریموک به آدرس angularjs.org بروید. همچنین می‌توانید با استفاده CDN گوگل یا CDNJS آنرا در پروژه‌ی خود اضافه نمایید.

نسخه AngularJSای که در دوره آموزش AngularJS استفاده می‌شود، نسخه‌ی ۱٫۴٫۸ می‌باشد. که با نسخه‌های بعدی ۱٫۴٫* هم سازگار می‌باشد. اما تضمینی برای سازگاری با نسخه‌‌ی ۱٫۵٫* وجود ندارد.

در نهایت آنرا با استفاده از تگ script در HTML وارد کنید.

<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js"></script>

پس از اضافه کردن فریمورک به صفحه، می‌بایست به AngularJS بگویید که کدام بخش از HTML را مدیریت کند. به یاد‌ دارید که AngularJS یک توسعه‌دهنده‌ی HTML است. در نتیجه، بجای نوشتن کد جاوااسکریپت برای فعال کردن آن، می‌بایست به کد HTML خود عباراتی را اضافه کنید که تنها AngularJS آنرا می‌فهمد. این عبارت ng-app یک صفت (attribute) است که آنرا می‌توانید به هر المان DOM اضافه نمایید. برای مثال‌های این بخش آنرا به تگ body اختصاص می‌دهیم.

<body ng-app>
<!-- All Examples Code In This Section Added Here!-->
</body>

با اضافه نمودن این صفت به body یا html به AngularJS این قابلیت را می‌دهیم تا بر کل صفحه کنترل داشته باشد. اینگونه اختصاص دادن بیشتر برای اپلیکیشن‌های تک صفحه‌ای کاربرد دارد. اما شما می‌توانید آنرا به بلوک‌های کوچکتری هم اختصاص دهید تا بخش‌های دیگر را با کتابخانه‌ی دیگری مدیریت کنید یا حتی دو یا چند اپلیکیشن AngularJS در صفحه داشته باشید.

منتظر مراحل بعدی بودید؟ خیر! تمام شد. حالا AmgularJS به خوبی راه‌اندازی شده است.

عبارات Expressions

اگر شما با توجه به جاوااسکریپت محجوب آموزش دیده‌اید، مثال‌های آینده ممکن است برای شما خطرناک بنظر برسد! چون AngularJS به شما این اجازه را می‌دهد که HTML صفحه را با عبارات شبه‌جاوااسکریپت‌ مخلوط کنید. عبارات AngularJS می‌تواند هرگونه کد ساده و معتبر جاوااسکریپت باشد، اگرچه ساختار‌های کنترل جریان برنامه همچون حلقه‌ها و برخی چیز‌های دیگر غیرقابل استفاده هستند. لطفا از پیش‌داوری این فریمورک با این مثال‌ها خودداری کنید، چون در اینجا تنها می‌خواییم به شکل آزمون و خطا و ساده (نه لزوما توصیه‌شده) با AngularJS آشنا شویم.

برای مثال اول، بیایید دو عدد را با‌هم جمع ببندیم.

Adding number as AngularJS Expression {{1+1}}
view raw expressions.html hosted with ❤ by GitHub

با کلیک بر روی عبارت “expressions.html” می‌توانید به راحتی بصورت آنلاین کد را تغییر بدهید. لطفا اینکار را انجام دهید. عبارات مختلف را امتحان کنید. ببینید می‌توانید برای AngularJS مشکلی ایجاد کنید و کاری کنید تا عبارت به مشکل بر بخورد؟

هنگامی که AngularJS نتواند عبارتی را پردازش کند، متن اصلی را نشان می‌دهد و در هنگامی که خطایی بوجود بیاید، هیچ چیزی‌ را نشان نمی‌دهد.

عبارت {{}}  جداکننده‌ی قالب (Template Delimiter) است. اگر قبلا با موتور‌های قالب Mustache یا Handlebars کار کرده باشید، حتما با این جداکننده‌ی قالب آشنایی دارید. می‌توان به AngularJS بعنوان یک موتور قالب (Template Engine) هم نگاه کرد. AngularJS تمام کد‌هایی را که در بین ng-app قرار می‌دهید را بصورت یک قالب در نظر می‌گیرد که در هنگام لود شدن صفحه آنرا کامپایل می‌کند و در هنگام تغییرات آنرا بازطراحی میکند. (اگر با موتور‌های قالب آشنایی ندارید، نگران نباشید. در ادامه‌ی دوره این مفهوم را هم بررسی می‌کنیم.)

حالا چطور است که یک شرط را در عبارت تست کنیم.

String equals to Number? {{'1' == 1}}

نتیجه شرط برای جاوااسکریپت درست است. اگر برای شما متعجب کننده است، بهتر است ساختار‌های شرطی جاوااسکریپت را دوباره مطالعه کنید و پس از آن کد بالا‌ را تغییر داده و بجای == از === استفاده کنید.

شرط === را شرط برابری سخت‌گیر می‌نامند. در این شرط هیچگونه تبدیل نوع‌ای اتفاق نمی‌افتد و برابری نوع داده عملوند‌ها نیز بررسی می‌شود.شرط == را شرط برابری (Equality) می‌نامند. در این شرط اگر دو عملوند از یک جنس نباشند تبدیل نوع عملوند انجام می‌پذیرد و سپس با استفاده از شرط برابری سخت‌گیر(Strict Equality) باهم مقایسه می‌شوند.

حالا بیاییم عبارتی از نوع رشته را امتحان کنیم. در این مثال، می‌بینیم که به توابع استاندارد جاوااسکریپت همچون توابع نوع رشته در عبارات دسترسی داریم.

{{"Angular" + "js".toUpperCase() + " FRAMEWORK".toLowerCase()}}

حالا فکر می‌کنید می‌توانید هر کد جاوااسکریپت که خواستید را در عبارات بکار ببرید؟ اصلا اینگونه نیست.

<!-- Invalid AngularJS Expression !-->
{{alert("https://blog.allii.ir/")}}

قطعا شما نمی‌توانید از alert استفاده کنید. همچنین شما از بسیاری از اشیاء سراسری (Global Objects) جاوااسکریپت همچون Math، Number، Date و… نمی‌توانید استفاده کنید.

سعی کنید عبارت alert("https://blog.allii.ir/") را به عبارت‌های دیگری همچون  parseInt("1") یا  Number.NaN یا Date.now() و یا Math.random() عوض کنید. اگر چیزی نمایش داده نشد، به این معنی است که AngularJS تجزیه و تحلیل عبارت را رد کرده است.

می‌دانم از سروکله زدن با عبارات خسته شده‌اید و فکر می‌کنید همه چیز را راجع به عبارات در AngularJS می‌دانید. اما هنوز چند نکته‌ی دیگر در مورد عبارات باقی مانده است. بیایید ببینیم می‌توانیم متغییری در عبارات تعریف کنیم؟

I'm variable * 3: {{variable = 5; variable * 3}}

می‌بینیم که می‌شود متغییر در عبارات تعریف کرد. اما قبل از نام متغییر var قرار دهید. خطا داد؟ اگر متن عبارت را مشاهده می‌کنید، یعنی خطایی رخ داده. نگران نباشید. بهترین راه برای یادگیری، خطا کردن است.

حالا که می‌خواهیم سعی و خطا کنیم، چرا بررسی نکنیم که آیا با تعریف یک متغییر در یک عبارت، می‌توانیم آنرا در عبارت دیگر استفاده کنیم.

{{variable = 1}} === {{variable}}

چه اتفاقی می‌افتد اگر جای دو عبارت را تغییر دهید. یعنی تعریف متغییر را بعد از استفاده از آن در عبارت بیاورید. امتحان کنید. بدرستی نتیجه داد؟ چگونه می‌توان این رفتار را توضیح داد؟

در جاوااسکریپت برخلاف بسیاری از زبان‌های دیگر، تنها یک تابع، حوزه‌ی جدید می‌سازد. کلیه‌ی عبارات و ساختار‌های دیگر، همه در حوزه‌ی سراسری قرار می‌گیرند.

عمل‌گر سه‌تایی چطور؟

I Have {{variable = 3; (variable > 2) ? "more than ": "less than"}} 2 Apples.

خوشبختانه عملگر‌سه‌تایی به خوبی عمل می‌کند. این عملگر بدلیل حجم بسیار کمی که اشغال می‌کند در قالب‌ها بسیار بکار می‌آید.

حالا بیایید عملگر ++ را امتحان کنیم.

{{variable = 5; ++variable}}

به نظر می‌رسد نمی‌توان از عملگر افزایش استفاده کرد.

در نهایت بیایید حلقه‌ را امتحان کنیم. در این مثال از تعریف متغییر با var و همچنین استفاده از عملگر افزایش ++ ، بدلیل اینکه می‌دانیم مشکل‌دار هستند خودداری کرده‌ایم.

{{for (i = 0; i < 100; i = i + 1) {i}}}

میبینیم حلقه‌ی for اجرا نشده است. همچنین در console مرورگرتان خطایی با عنوان $parse:syntax نمایش داده می‌شود. اما این حلقه، یک حلقه‌ی معتبر جاوااسکریپت است.

در این بخش به خوبی با عبارات AngularJS، قابلیت‌ها و محدودیت‌هایش آشنا شدیم. شاید به نظر برسد که استفاده از جاوااسکریپت در قالب کار خوبی نباشد. اما، با توجه به محدودیتی که AngularJS برای عباراتش در نظر گرفته است، نمی‌توان در عبارات آن دستورات متعدد و گیج کننده‌‌ی جاوااسکریپت را نوشت. تنها می‌توان دستورات ساده‌ای که به راحتی قابل رفع عیب هستند را بکار برد.

رهنمود‌ها Directives

رهنمودها (Directives) روح و جان AngularJS هستند. برای شروع، بهتر است آنها را به‌چشم HTML سفارشی نگاه کنید. سفارشی به این معنی‌ که با آنچه که در استاندارد‌های HTML ویرایش‌های گوناگون که تابحال مشاهده کرده‌اید متفاوت هستند. در بیشتر اوقات رهنمودها به شکل خواص (Attributes) مشاهده می‌شوند که همانند دیگر خواص در المان‌های HTML مورد استفاده قرار می‌گیرند. رهنمودهای داخلی AngularJS که همراه با فریمورک ارایه می‌شوند، با پیشوند ng شروع می‌شوند که به دو حرف در اسم فریمورک یعنی AngularJS اشاره دارد. همچنین در حال حاضر تعداد بسیار زیادی رهنمود‌های غیر رسمی نیز برای استفاده وجود دارد. نکته‌ی کلیدی رهنمودها این است که هرگاه قطعه کد طولانی به زبان Javascript در بخشی از اپلیکیشن تحت وب‌تان مشاهده کردید، با خود بگوید که “حتما یک رهنمود برایش وجود دارد”.

تا‌ اینجای آموزش، ما از یک رهنمود استفاده کرده ایم. بیاد می‌آورید؟ برای اینکه به AngularJS بفهمانیم که در کجای صفحه‌ی اپلیکیشن انجام وظیفه کند، ما از خاصیت ng-app بر روی تگ body استفاده کردیم. در این مورد ما مقدار (Value)ای به این خاصیت تخصیص ندادیم. به این مقادیر که می‌شود به راحتی با قرار دادن =""، همانند تمامی خاصیت‌ها و مقادیر آن که قبلا در HTML از آن‌ها استفاده کرده‌ایم، در مقابل نام رهنمود به آن تخصیص دهیم،  آرگومان‌ها (Arguments)ی رهنمود گفته می‌شود. برای مثال می‌توان نام اپلیکیشن را با تغییر ng-app به ng-app="testApp" مشخص نماییم. ( نام اپلیکیشن در واقع نام یک ماژول (Module) است. ماژول بخش مهمی از معماری AngularJS را تشکیل می‌دهد که در بخش ماژول‌ها در آینده به آن خواهیم پرداخت.)

در ادامه با چند رهنمود ساده‌ی AngularJS با استفاده از مثال‌های متعدد آشنا خواهیم شد.

رهنمود ng-bind

برخی از رهنمود‌ها رشته‌ای از عبارات را بعنوان آرگومان قبول می‌کنند و آنرا تجزیه (Parse) می‌نمایند. (برای فهمیدن آرگومان‌های مورد قبول هرکدام از رهنمود‌های داخلی AngularJS می‌بایست به مستندات API مراجعه کنید.) برای مثال، رهنمود ng-bind برای تجزیه کردن عبارات بکار می‌رود. دقیقا مشابه کاری که {{}} ،که در بخش قبلی از آن برای معرفی عبارات استفاده کردیم، انجام می‌داد. برای نمونه:

Adding number as AngularJS ng-bind Directive: <span ng-bind="1+1"></span>
view raw ng-bind-simple.html hosted with ❤ by GitHub

با اینکه نتیجه‌ی این مثال با اولین مثال این بخش برابر است، اما یک تفاوت بسیار مهم در نحوه‌ی رفتار ng-bind وجود دارد. آنهم اینکه، محتوای المان، یعنی همان عبارت در مقابل ng-bind، که این رهنمود را به آن اختصاص دادید، هنگامی که قالب بطور کامل تجزیه و تحلیل شد و آماده‌ی نمایش شد جایگزین می‌شود. بنابراین، تکنیک توصیه‌ شده برای قرار دادن عبارت بعنوان محتوای یک المان، استفاده از رهنمود ng-bind و قرار ندادن هیچ چیزی بعنوان محتوای المان است. چون در این‌صورت تا هنگامی‌که AngularJS قالب خام اپلیکیشن را تجزیه و تحلیل نکرده و آماده‌ی نمایش آن نشده است، مقداری در محتوای المان نمایش داده نشود. این ویژگی می‌تواند بسیار مفید باشد. چرا؟ چون با توجه به امکانات کاربر استفاده کننده و همچنین حجم و رفتار اپلیکیشن AngularJS شما، ممکن است تاخیری قابل ملاحظه از زمانیکه صفحه درخواست داده می‌شود و تا زمانیکه توسط AngularJS بطور کامل تجزیه و تحلیل و در نهایت نمایش داده شود، بوجود بیاید. در طی این تاخیر زمانی، در صورت استفاده از {{}} برای عبارات، عبارات به همان شکل جایگزین نشده در صفحه نمایش داده می‌شوند. اما در صورت استفاده از رهنمود ng-bind یک المان خالی و بدون محتوا نمایش داد می‌شود و از این مشکل جلوگیری می‌شود.

در برخی موارد که اپلیکیشن AngularJS بسیار بزرگ و حجیم می‌شود، ممکن است بخواهید این مشکل سو‌سو زدن محتوای اپلیکیشن را با مخفی کردن بخش بزرگ و یا حتی کل اپلیکیشن از دید کاربر، تا زمانیکه AngularJS آماده نشده است، برطرف کنید. برای این‌کار براحتی می‌توانید از رهنمود ng-cloak استفاده کنید.

رهنمود ng-init

بیاد می‌آورید که چگونه یک متغییر را در یک مثال در بخش عبارت‌ها مقداردهی اولیه کردیم تا ببینیم آیا اینکار امکان پذیر است یا نه؟ (مثال expressions-variables.html). برای اینکار نیز یک رهنمود در AngularJS وجود دارد. با استفاده از ng-init، شما می‌توانید متغییر‌ها را برای استفاده در هر کجای المان که به آن اختصاص داده شده است، مقداردهی اولیه کنید.

<div ng-init="variable = 5">
This is my variable: {{variable}}<br/>
And my variable * 3 is:<span ng-bind="variable*3"></span>
</div>
view raw ng-init-simple.html hosted with ❤ by GitHub

برای جدا کردن احکام مختلف از نقطه‌ویرگول (Semicolons) یا بهتر بگویم از ; استفاده کنید. بدین‌گونه شما می‌توانید به هر تعداد که می‌خواهید متغییر با مقدار اولیه مشخص کنید.

<div ng-init="variable1 = 10; variable2 = 5; variable3='Divided By'">
{{variable1}} {{variable3}} {{variable2}}: {{variable1/variable2}}
</div>

شاید به نظرتان برسد که بهتر است متغییر‌ها خود را در یک شیء مرتب کنید.

<div ng-init="variable= {firstNumber: 10, secondNumber: 5, divideText: 'Divided By'}">
{{variable.firstNumber}} {{variable.divideText}} {{variable.secondNumber}}: {{variable.firstNumber/variable.secondNumber}}
</div>

آرایه‌ها هم گاهی بکار می‌آیند.

<div ng-init="variable= ['http://','blog','allii','ir']">
My weblog url {{variable[0]}}{{variable[1]}}.{{variable[2]}}.{{variable[3]}} as array: {{variable}}
</div>

نکته‌ی بسیار مهمی که وجود دارد، دقت در نام‌گذاری و همچنین دسترسی به ویژگی‌های یک متغییر در قالب‌های AngularJS است. احتمالا شما خطا‌هایی قالب زیر را به راحتی با نگاه کردن می‌توانید تشخیص دهید. اما انتظار هیچگونه کمکی از طرف AngularJS را نداشته باشید. AngularJS بی سر و صدا تمامی دسترسی‌های نادرست به ویژگی‌های متغییر‌های از نوع شیء یا آرایه را نادیده می‌گیرد. دسترسی‌هایی همچون ویژگی‌های تو در تو (Nested) برای یک والد که اصلا تعریف نشده است و یا دسترسی به خارج از محدوده‌ی آرایه‌ها.

<div ng-init="validVariable = {property1: 'Im a property', arrayProperty: ['1','2']}">
-{{invalidVariable.arrayProperty[1]}}<br/>
-{{validVariable.invalidProperty.property1}}<br/>
-{{validVariable.arrayProperty[2]}}
</div>

تا اینجا به نظر می‌رسد که AngularJS در رهنمود ng-bind بی‌قید و شرط است و دست برنامه‌نویس را کاملا باز گذاشته است. به نظرتان در این رهنمود می‌توانیم یک تابع تعریف کنیم و از آن استفاده کنیم؟

<div ng-init="myFunction = function(){ return 1; }">
My function return is: {{myFunction()}}
</div>

نه! آنطور که به نظر می‌رسد هم این رهنمود بی قید و شرط نیست. تعریف تابع مجاز نمی‌باشد و AngularJS یک خطا از نوع $parse:syntax پرتاب می‌کند که در کنسول جاوااسکریپت در مرورگر قابل مشاهده است. جای مناسب و درست برای تعریف تابع برای استفاده در عبارات AngularJS، درون کنترل‌گرها (Controllers) می باشد. کنترل‌گرها در ادامه، در اولین بخش بعد از مبانی معرفی خواهند شد. اما بطور کلی، در واقع کنترل‌گرها بخش مناسبی برای آماده‌سازی داده‌ها برای بخش نمایش (View) هستند. رهنمود ng-bind که در این بخش با آن آشنا شدیم و کمی خوش‌ گذراندیم، در حقیقت برای نام‌گذاری مستعار متغییرها (Aliasing Variables) مورد استفاده قرار می‌گیرد که در بخش‌های بعدی آموزش به این مورد نیز خواهیم پرداخت.

رهنمود ng-non-bindable

به هر حال، اگر شما نیاز داشتید تا بخشی از سند HTML را در مقابل تجزیه‌ی و تحلیل AngularJS محافظ کنید، می‌توانید به آن بخش رهنمود ng-non-bindable را اختصاص دهید.

<div >
Are there just <span ng-bind="1+1"></span> Oranges, or {{1+2}} Apples?
</div>


رهنمود ng-non-bindable را بردارید و نتیجه را ببینید.

رهنمودهای ng-show و ng-hide

حالا زمان آن فرا رسیده است تا چیزی فراتر از تجزیه و تحلیل عبارات را بررسی کنیم. برای شروع، چگونه می‌توانیم یک المان HTML را بصورت شرطی نمایش دهیم یا مخفی کنیم؟

بعنوان یک توصیه از تجربه‌ی شخصی خودم، راه حلی که نباید برای انجام اینکار بکار ببرید را توضیح می‌دهم. اوایل که با AngularJS آشنا شده بودم و از آن استفاده می‌کردم، نیاز شد تا یک فرم را بعد از اینکه کاربر با موفقیت آنرا به ثبت رساند، مخفی کنم. درون کنترل‌گری که برای رسیدگی به درخواست‌های کاربر نوشته بودم، از تابع jQuery.hide() برای اینکار استفاده کردم. همانطور که انتظار می‌رفت به خوبی عمل‌ کرد. با اینحال، در نظر داشته باشید که “حتما یک رهنمود برایش وجود دارد”. در حقیقت دو رهنمود: ng-show و ng-hide.

<div id="form_wrapper" ng-init="notSubmitted = true">
<form ng-show="notSubmitted">
<input type="text" name="feedback"/>
<input type="submit" value="Submit Feedback"/>
</form>
<div ng-hide="notSubmitted">Thanks for submitting your feedback!</div>
</div>

مقدار notSubmitted را در مثال قبل از  true  به false تغییر بدید و نتیجه را مشاهده کنید. از آنجا که AngularJS همواره مراقب تغییرات است، شما می‌توانید مقدار متغییر notSubmitted را هر کجا که خواستید تغییر دهید و در نتیجه‌ی آن لایه‌ی نمایش (View) اپلیکیشن به‌روزرسانی میشود.

بهتر است در ادامه کمی به لایه‌های زیرین‌تر AngularJS برویم و بفهمیم که متغییر‌هایی همچون notSubmitted در حقیقت چه هستند.

حوزه‌ها Scopes

در اپلیکیشن‌هایی که با AngularJS نوشته شده‌اند، حوزه‌ها ارایه دهنده‌ی یک “تک منبع حقیقت” یا “تنها منبع حقیقت” (SSoT: Single Source of Truth) هستند.

تک منبع حقیقت: این مفهوم در سامانه‌هایی که مبتنی بر اطلاعات هستند معنی پیدا می‌کند. و به این معنی است که نحوه‌ی ذخیره سازی اطلاعات بگونه‌ای باشد که یک اطلاع یا داده، تنها و تنها فقط یکبار ذخیره شده باشد. برای مثال، یک دیتابیس SQL را در نظر بگیرید. در این دیتابیس ما جدولی از کاربر‌ها داریم بنام user. باید بگونه‌ای این دیتابیس طراحی شده باشد که به ازای هر کاربر، تنها و تنها یک سطر در جدول user مورد استفاده قرار گرفته باشد و هر کجا که از این کاربر می‌خواهیم استفاده کنیم، تنها با ارجاع به آن باشد. 

اما در AngularJS، اینکه می‌گوییم حوزه‌ها ارایه دهنده‌های یک SSoT در اپلیکیشن ما هستند، به این معنی است که اهمیت ندارد که در چه تعداد و در چه جاهایی از لایه‌ی نمایش شما داده‌ای را نمایش می‌دهید، برای تغییر آن شما می‌بایست تنها در یک جا آنرا تغییر دهید (درون خاصیت حوزه)، و این تغییر بصورت خودکار در سراسر لایه‌ی نمایش منتشر شود.

به این دلیل که این تجزیه و بازتجزیه‌های متوالی نیازمند یک زیرساخت در زبان برنامه‌نویسی پایه هستند، اشیاءای که به حوزه‌ها تخصیص داده می‌شوند اشیاء معمولی زبان هستند. ممکن است با مفهوم POJO آشنایی داشته باشید. کلیه‌ی اشیاءای که به حوزه‌ها تخصیص داده می‌شوند از نوع POJO ها هستند.

POJO: این مفهوم برای بار اول در زبان Java معرفی شد و از سر‌نام Plain Old Java Object گرفته شد. در زبان‌های مختلف به آن نام‌های متفاوتی داده شده است. در اینجا ما به آن Plain Old Javascript Object می گوییم. در زبان جاوا به کلاس هایی گفته می‌شود که از هیچ کلاس دیگری ارث بری نداشته باشند و جزء فریمورک خاصی نباشند. در جاوااسکریپت به Object هایی گفته می‌شود که بطور مستقیم از نوع درون‌ساخت Object زبان ساخته شده باشند. همانطور که می‌دانید در جاوااسکریپت ما می‌توانیم با تعریف یک Prototype برای Object رفتار آنرا تغییر دهیم و کاری کنیم تمام Object های ساخته شده از روی این Object درون‌ساخت از این رفتار جدید ارث بری داشته باشد. اینگونه اشیاء را دیگر نمی‌توان POJO در نظر گرفت.

البته اینکه ما این اشیاء را POJO در نظر میگیریم، با کمی ارفاق است. چون AngularJS برای اینکه بتواند از تغییرات درون Object ها مطلع شود، یک مکانیزم تشخیص تغییر را به کلیه‌ی Objectها اضافه میکند. اما بخاطر سادگی و سربار کمی که به Object ها اضافه می‌کند می‌توانیم آنهارا POJO در نظر بگیریم.

البته ناگفته نماند که در استاندار‌های ECMA از چیزی به نام Object.Observe نام برده شده است که همین قابلیت را بصورت درون‌ساخت برای Object ها در نظر میگیرد. اگر روزی این قابلیت به Object های جاوااسکریپت اضافه شود، دیگر می‌توان اشیاء AngularJS را POJO خالص در نظر گرفت

ما به این اشیاء تخصیص یافته به حوزه‌ها در ادامه خواص حوزه (Scope Properties) می‌گوییم. در مثال‌های قبلی ما با این خواص کار کرده ایم. یادتان می‌آید که ما متغییر‌هایی را در رهنمود ng-init تعریف کردیم و از آن استفاده کردیم؟ در حقیقت آنها خواص حوزه بودند. یادتان می‌آید که از شما خواستم با اضافه کردن کلمه کلیدی var قبل از متغییر‌ها در عبارات آنها را تعریف کنید؟ دیدیم که اینکار مجاز نمی‌باشد. چون آن‌چه را که من قبلا بعنوان متغییر عنوان می‌کردم در حقیقت یک خاصیت برای شی‌ء حوزه‌ای بود که بصورت خودکار در پشت صحنه برایمان ساخته شده بود.

بین خاصیت یک شیء و متغییر تفاوت اساسی وجود دارد. مطالعه بیشتر

در بخش‌های آینده به مفهوم حوزه (Scope) بیشتر خواهیم پرداخت و تنها در انتهای این بخش، به اینکه چگونه می‌توانیم از این خواص حوزه استفاده کنیم با مثال‌هایی بیشتر آشنا خواهیم شد.

انقیاد داده دو-طرفه Two-way Data Binding

در مثال‌های قبلی این بخش، ما با مفهوم انقیاد داده یک-طرفه آشنا شدیم و از آن استفاده نمودیم. در کلیه‌ی مثال‌های قبلی از این گونه انقیاد داده استفاده کردیم. به این مفهوم که لایه‌ی نمایش تنها نمایش دهنده خاصیت ذخیره شده بود و در تغییر آن نقشی نداشت و تنها با تغییر مقدار در حوزه، این تغییر به لایه‌ی نمایش منتقل می‌شد. اما در انقیاد داده دو-طرفه ما به لایه‌ی View این امکان را می‌دهیم که بتواند خاصیت حوزه را تغییر دهد و  آنرا به گوش دیگران برساند.

برای مثال اول ما از رهنمود ng-click استفاده خواهیم کرد. این رهنمود شبیه صفت onclick است که با آن می‌شد با رویداد کلیک موس یک تابع یا عبارت جاوااسکریپت را اجرا کرد. برای همین مثال (ng-show-ng-hide-simple.html) را بگونه‌ای تغییر می‌دهیم تا بتوان با کلیک بر روی submit، متغییر را تغییر داد.

<div id="form_wrapper" ng-init="notSubmitted = true">
<form ng-show="notSubmitted">
<input type="text" name="feedback"/>
<input type="submit" value="Submit Feedback" ng-click="notSubmitted = !notSubmitted"/>
</form>
<div ng-hide="notSubmitted">Thanks for submitting your feedback!</div>
</div>
view raw scopes-ng-click.html hosted with ❤ by GitHub

آرگومانی که رهنمود ng-click دریافت می‌کند می‌تواند هر عبارتی باشد. همچنین یک رهنمود همه‌کاره است که به رفتار در برار خواص حوزه‌ای که در آن استفاده شده است، محدود نمی‌باشد. این مثال خیلی ساده بود. بنظرتان چگونه می‌توانیم بصورت پیشرفته‌تری به انقیاد داده دو-طرفه بپردازیم؟

رهنمود ng-model

بنظر می‌رسد که هیچ معرفی برای انقیاد داده‌ها در AngularJS با مثال یک ورودی متنی و یک رشته کامل نمی‌باشد. حالا نوبت ماست!

<input type="text" ng-model="textInput">
My input value is "<span ng-bind="textInput"></span>". Type something!

در این مثال ما به input رهنمود ng-model را اضافه کردیم. AngularJS هم آنرا با رهنمود درون‌ساخت input خود جایگزین کرد!

خب چه کار دیگری بنظرات می‌توانیم انجام بدهیم؟ خب، همیشه‌ می‌توان با استفاده از رهنمود ng-init مقدار دهی اولیه انجام دهیم.

<input type="text" ng-init="textInput = 'Initial'" ng-model="textInput">
My input value is "<span ng-bind="textInput"></span>". Type something!

حالا بیایید انواع دیگر ورودی را بررسی کنیم. Checkbox چطور است؟

<input type="checkbox" ng-init="checkboxInput = true" ng-model="checkboxInput">
My input is checked: "<span ng-bind="checkboxInput"></span>". Change it!

اما می‌توان مقادیر Checkbox را بجای مقادیر بولی (Boolean) یعنی true و false را با رشته‌ها جایگزین کرد. همانطور که قبلا گفتیم “حتما یک رهنمود برایش وجود دارد”، پس برای اینکار هم باید از رهنمود‌ها استفاده کنیم.

<input type="checkbox" ng-init="checkboxInput = 'Checked'" ng-model="checkboxInput"
ng-true-value="'Checked'" ng-false-value="'not Checked'">
My input is "<span ng-bind="checkboxInput"></span>". Change it!

رهنمود select فریمورک نیز همانگونه که انتظار می‌رود به خوبی عمل می‌کند.

<select ng-init="selectOption = 'Happy'" ng-model="selectOption">
<option value="Happy">Happy</option>
<option value="Angry">Angry</option>
<option value="Sad" selected>Sad</option>
</select>
You are "<span ng-bind="selectOption"></span>", not?. Please Select!

همانطور که می‌بیند این رهنمود مقدار selected را نادیده می‌گیرد. رهنمود ng-init را حذف کنید. آیا مقدار Sad انتخاب می‌شود؟ پس selected در رهنمود select نادیده گرفته می‌شود.

با وجود سه‌تا گزینه برای انتخاب، مثال آخر به نظر می‌رسد بهتر است با گروهی از radio buttonها جایگزین شود. مشکلی نیست. انجامش دهیم!

<div ng-init="radioButton = 'Happy'">
<input type="radio" value="Happy" ng-model="radioButton"/> Happy
<input type="radio" value="Angry" ng-model="radioButton"/> Angry
<input type="radio" value="Sad" ng-model="radioButton"/> Sad
You are "<span ng-bind="radioButton"></span>", not?. Please Select!
</div>

تا بدینجا شما تجربه‌های واقعی در رابطه با پالایش داده‌های یک حوزه با استفاده از رهنمود‌های AngularJS پیدا کرده اید. در نظر داشته باشید که تعداد خیلی زیادی از این رهنمود‌های درون‌ساخت وجود دارد که هنوز معرفی نشده اند. در ادامه این سری آموزش به آنها نیز خواهیم پرداخت.

نتیجه گیری

در اول این بخش از شما خواستیم که به AngularJS بعنوان یک فریمورک جاوااسکریپت نگاه نکنید، بلکه آنرا توسعه‌دهنده‌ی HTML در نظر بگیرید. با توجه به مصاحبه‌ای که با سازنده‌ی AngularJS، یعنی Miško Hevery انجام شده، AngularJS در ابتدا بعنوان یک راه موثرتر برای توسعه‌دهندگان رابط‌کاربری وب برای بهتر‌ کردن صفحه وب در نظر گرفته شده بود، سپس از دل آن فریمورک جاوااسکریپت بیرون آمده است.

همچنین دیدیم که AngularJS براساس همان ویژگی‌ها و قوانینی که در HTML داشتیم عمل می‌کند. ویژگی‌ها و قوانینی که با آن کاملا آشنا هستیم.

تا بدینجا، ما از AngularJS با استفاده از کد جاوااسکریپت استفاده نکرده‌ایم. اما در اپلیکیشن‌های واقعی AngularJS همیشه از کنترل‌گر‌ها، سرویس‌ها و مسیر‌یاب‌ها استفاده می‌شود. همچنین از ماژول‌ها، تزریق وابستگی و AJAX نیز به وفور استفاده می‌شود. تمامی این موارد که گفته شد در این دوره مورد بررسی قرار خواهد گرفت. اما ذکر این نکته ضروری بنظر میر‌سد که بهترین سرعت توسعه با AngularJS زمانی بدست می‌آید که همواره بیاد داشته باشیم که “حتما یک رهنمود برایش وجود دارد”. یعنی بجای اینکه بخواهیم با کد جاوااسکرپت کاری را انجام دهیم، بهتر است خود HTML را توسعه دهیم و به آن قابلیتی را که می‌خواهیم بدهیم. نوشتن رهنمود‌های سفارشی (Custom Directives) یکی از چالش‌های اساسی AngularJS است. برای همین از همین ابتدا رهنمود‌ها را معرفی کردیم تا در ادامه و در طول آموزش همواره آنها را در نظر داشته باشید تا در نهایت وارد نوشتن رهنمود‌های سفارشی شویم.

سخن آخر

در آخر می خواهم آدرس مخزن کد‌های پروژه را اختیار شما قرار دهم. این کد‌ها در github موجود است. همچنین می‌توانید هرکدام از مثال‌هایی که در صفحه آمده بصورت لایو ویرایش کنید.

آدرس Github کد‌های دوره‌ی آموزش: https://github.com/alirdn/angularjs-beginner-intermediate-course