برخی از امکاناتی که تقویمهای مشابه دارند که اگر در این تقویم هم پیش بینی شود بهتر است.
تقویم با jQuery به فرموده آقای یوسفی : محدود کردن انتخاب تاریخ
یا تقویم ترجمه آقای هاشمی نژاد : انتخاب تاریخهای محدود بین دو تاریخ
بنده میخواستم نظرم را به عنوان بازخورد ثبت کنم ولی فکر کردم اینجا ثبت کنم بهتره
اینکه datepicker رو به datetimepicker تبدیل کنیم
بتوانیم یک نمونه یا راهنمای توسعه برای همکاران جهت ادامه راه پرارزش شما ارائه دهیم.
محصول را با برخی از ابزارهای معروف مانند KENDO UI یا Telerik که مصرف کنندگان بسیار زیادی دارند مقایسه کنیم و امکاناتشان را در کنار هم تشریح کنیم
MVC Scaffolding #1
کل سری ASP.NET MVC
به همراه کل سری EF Code First
MVC Scaffolding چیست؟
MVC Scaffolding ابزاری است برای تولید خودکار کدهای «اولیه» برنامه، جهت بالا بردن سرعت تولید برنامههای ASP.NET MVC مبتنی بر EF Code First.
بررسی مقدماتی MVC Scaffolding
امکان اجرای ابزار MVC Scaffolding از دو طریق دستورات خط فرمان Powershell و یا صفحه دیالوگ افزودن یک کنترلر در پروژههای ASP.NET MVC وجود دارد. در ابتدا حالت ساده و ابتدایی استفاده از صفحه دیالوگ افزودن یک کنترلر را بررسی خواهیم کرد تا با کلیات این فرآیند آشنا شویم. سپس در ادامه به خط فرمان Powershell که اصل توانمندیها و قابلیتهای سفارشی MVC Scaffolding در آن قرار دارد، خواهیم پرداخت.
برای این منظور یک پروژه جدید MVC را آغاز کنید؛ ابزارهای مقدماتی MVC Scaffolding از اولین به روز رسانی ASP.NET MVC3 به بعد با VS.NET یکپارچه هستند.
ابتدا کلاس زیر را به پوشه مدلهای برنامه اضافه کنید:
using System; using System.ComponentModel; using System.ComponentModel.DataAnnotations; namespace MvcApplication1.Models { public class Task { public int Id { set; get; } [Required] public string Name { set; get; } [DisplayName("Due Date")] public DateTime? DueDate { set; get; } [DisplayName("Is Complete")] public bool IsComplete { set; get; } [StringLength(450)] public string Description { set; get; } } }
همانطور که ملاحظه میکنید در قسمت قالبها، تولید کنترلرهایی با اکشن متدهای ثبت و نمایش اطلاعات مبتنی بر EF Code First انتخاب شده است. کلاس مدل نیز به کلاس Task فوق تنظیم گردیده و در زمان انتخاب DbContext مرتبط، گزینه new data context را انتخاب کرده و نام پیش فرض آنرا پذیرفتهایم. زمانیکه بر روی دکمه Add کلیک کنیم، اتفاقات ذیل رخ خواهند داد:
الف) کنترلر جدید TasksController.cs به همراه تمام کدهای Insert/Update/Delete/Display مرتبط تولید خواهد شد.
ب) کلاس DbContext خودکاری به نام MvcApplication1Context.cs در پوشه مدلهای برنامه ایجاد میگردد تا کلاس Task را در معرض دید EF Code first قرار دهد. (همانطور که عنوان شد یکی از پیشنیازهای بحث Scaffolding آشنایی با EF Code first است)
ج) در پوشه Views\Tasks، پنج View جدید را جهت مدیریت فرآیندهای نمایش صفحات Insert، حذف، ویرایش، نمایش و غیره تهیه میکند.
د) فایل وب کانفیگ برنامه جهت درج رشته اتصالی به بانک اطلاعاتی تغییر کرده است. حالت پیش فرض آن استفاده از SQL CE است و برای استفاده از آن نیاز است قسمت 15 سری EF سایت جاری را پیشتر مطالعه کرده باشید (به چه اسمبلیهای دیگری مانند System.Data.SqlServerCe.dll برای اجرا نیاز است و چطور باید اتصال به بانک اطلاعاتی را تنظیم کرد)
معایب:
کیفیت کد تولیدی پیش فرض قابل قبول نیست:
- DbContext در سطح یک کنترلر وهله سازی شده و الگوی Context Per Request در اینجا بکارگرفته نشده است. واقعیت یک برنامه ASP.NET MVC کامل، داشتن چندین Partial View تغدیه شونده از کنترلرهای مختلف در یک صفحه واحد است. اگر قرار باشد به ازای هر کدام یکبار DbContext وهله سازی شود یعنی به ازای هر صفحه چندین بار اتصال به بانک اطلاعاتی باید برقرار شود که سربار زیادی را به همراه دارد. (قسمت 12 سری EF سایت جاری)
- اکشن متدها حاوی منطق پیاده سازی اعمال CRUD یا همان Create/Update/Delete هستند. به عبارتی از یک لایه سرویس برای خلوت کردن اکشن متدها استفاده نشده است.
- از ViewModel تعریف شدهای به نام Task هم به عنوان Domain model و هم ViewModel استفاده شده است. یک کلاس متناظر با جداول بانک اطلاعاتی میتواند شامل فیلدهای بیشتری باشد و نباید آنرا مستقیما در معرض دید یک View قرار داد (خصوصا از لحاظ مسایل امنیتی).
مزیتها:
قسمت عمدهای از کارهای «اولیه» تهیه یک کنترلر و همچنین Viewهای مرتبط به صورت خودکار انجام شدهاند. کارهای اولیهای که با هر روش و الگوی شناخته شدهای قصد پیاده سازی آنها را داشته باشید، وقت زیادی را به خود اختصاص داده و نهایتا آنچنان تفاوت عمدهای هم با کدهای تولیدی در اینجا نخواهند داشت. حداکثر فرمهای آنرا بخواهید با jQuery Ajax پیاده سازی کنید یا کنترلهای پیش فرض را با افزونههای jQuery غنی سازی نمائید. اما شروع کار و کدهای اولیه چیزی بیشتر از این نیست.
نصب بسته اصلی MVC Scaffolding توسط NuGet
بسته اصلی MVC Scaffolding را با استفاده از دستور خط فرمان Powershell ذیل، از طریق منوی Tools، گزینه Library package manager و انتخاب Package manager console میتوان به پروژه خود اضافه کرد:
Install-Package MvcScaffolding
Attempting to resolve dependency 'T4Scaffolding'. Attempting to resolve dependency 'T4Scaffolding.Core'. Attempting to resolve dependency 'EntityFramework'. Successfully installed 'T4Scaffolding.Core 1.0.0'. Successfully installed 'T4Scaffolding 1.0.8'. Successfully installed 'MvcScaffolding 1.0.9'. Successfully added 'T4Scaffolding.Core 1.0.0' to MvcApplication1. Successfully added 'T4Scaffolding 1.0.8' to MvcApplication1. Successfully added 'MvcScaffolding 1.0.9' to MvcApplication1.
پس از اینکه بسته MvcScaffolding به پروژه جاری اضافه شد، همان مراحل قبل را که توسط صفحه دیالوگ افزودن یک کنترلر انجام دادیم، اینبار به کمک دستور ذیل نیز میتوان پیاده سازی کرد:
Scaffold Controller Task
نکته و مزیت مهم دیگری که در اینجا در دسترس میباشد، سوئیچهای خط فرمانی است که به همراه صفحه دیالوگ افزودن یک کنترلر وجود ندارند. برای مثال دستور Scaffold Controller را تایپ کرده و سپس یک خط تیره را اضافه کنید. اکنون دکمه tab را مجددا بفشارید. منویی ظاهر خواهد شد که بیانگر سوئیچهای قابل استفاده است.
برای مثال اگر بخواهیم دستور Scaffold Controller Task را با جزئیات اولیه کاملتری ذکر کنیم، مانند تعیین نام دقیق کلاس مدل و کنترلر تولیدی به همراه نام دیگری برای DbContext مرتبط، خواهیم داشت:
Scaffold Controller -ModelType Task -ControllerName TasksController -DbContextType TasksDbContext
بهبود مقدماتی کیفیت کد تولیدی MVC Scaffolding
در همان کنسول پاروشل NuGet، کلید up arrow را فشار دهید تا مجددا دستور قبلی اجرا شده ظاهر شود. اینبار دستور قبلی را با سوئیچ جدید Repository (استفاده از الگوی مخزن) اجرا کنید:
Scaffold Controller -ModelType Task -ControllerName TasksController -DbContextType TasksDbContext -Repository
Scaffold Controller -ModelType Task -ControllerName TasksController -DbContextType TasksDbContext -Repository -Force
public class TasksController : Controller { private readonly ITaskRepository taskRepository; // If you are using Dependency Injection, you can delete the following constructor public TasksController() : this(new TaskRepository()) { } public TasksController(ITaskRepository taskRepository) { this.taskRepository = taskRepository; }
public interface ITaskRepository : IDisposable { IQueryable<Task> All { get; } IQueryable<Task> AllIncluding(params Expression<Func<Task, object>>[] includeProperties); Task Find(int id); void InsertOrUpdate(Task task); void Delete(int id); void Save(); }
پیاده سازی این اینترفیس در حالت متد Save آن شامل فراخوانی context.SaveChanges است. این مورد باید به الگوی واحد کار (که در اینجا تعریف نشده) منتقل شود. زیرا در یک دنیای واقعی حاصل کار بر روی چندین موجودیت باید در یک تراکنش ذخیره شوند و قرارگیری متد Save داخل کلاس مخزن یا سرویس برنامه، مخزنهای تعریف شده را تک موجودیتی میکند.
اما در کل با توجه به اینکه پیاده سازی منطق کار با موجودیتها به کلاسهای مخزن واگذار شدهاند و کنترلرها به این نحو خلوتتر گردیدهاند، یک مرحله پیشرفت محسوب میشود.
NoSQL و مایکروسافت
1) Azure table storage
Azure table storage در حقیقت یک Key-value store ابری است و برای کار با آن از اینترفیس پروتکل استاندارد OData استفاده میشود. علت استفاده و طراحی یک سیستم Key-value store در اینجا، مناسب بودن اینگونه سیستمها جهت مقاصد عمومی است و به این ترتیب میتوان به بازه بیشتری از مصرف کنندگان، خدمات ارائه داد.
پیش از ارائه Azure table storage، مایکروسافت سرویس خاصی را به نام SQL Server Data Services که به آن SQL Azure نیز گفته میشود، معرفی کرد. این سرویس نیز یک Key-Value store است؛ هرچند از SQL Server به عنوان مخزن نگهداری اطلاعات آن استفاده میکند.
2) SQL Azure XML Columns
فیلدهای XML از سال 2005 به امکانات توکار SQL Server اضافه شدند و این نوع فیلدها، بسیاری از مزایای دنیای NoSQL را درون SQL Server رابطهای مهیا میسازند. برای مثال با تعریف یک فیلد به صورت XML، میتوان از هر ردیف به ردیفی دیگر، اطلاعات متفاوتی را ذخیره کرد؛ به این ترتیب امکان کار با یک فیلد که میتواند اطلاعات یک شیء را قبول کند و در حقیقت امکان تعریف اسکیمای پویا و متغیر را در کنار امکانات یک بانک اطلاعاتی رابطهای که از اسکیمای ثابت پشتیبانی میکند، میسر میشود. در این حالت در هر ردیف میتوان تعدادی ستون ثابت را با یک ستون XML با اسکیمای کاملا پویا ترکیب کرد.
همچنین SQL Server در این حالت قابلیتی را ارائه میدهد که در بسیاری از بانکهای اطلاعاتی NoSQL میسر نیست. در اینجا در صورت نیاز و لزوم میتوان اسکیمای کاملا مشخصی را به یک فیلد XML نیز انتساب داد؛ هر چند این مورد اختیاری است و میتوان یک un typed XML را نیز بکار برد. به علاوه امکانات کوئری گرفتن توکار از این اطلاعات را به کمک XPath ترکیب شده با T-SQL، نیز فراموش نکنید.
بنابراین اگر یکی از اهداف اصلی گرایش شما به سمت دنیای NoSQL، استفاده از امکان تعریف اطلاعاتی با اسکیمای متغیر و پویا است، فیلدهای نوع XML اس کیوال سرور را مدنظر داشته باشید.
یک مثال عملی: فناوری Azure Dev Fabric's Table Storage (نسخه Developer ویندوز Azure که روی ویندوزهای معمولی اجرا میشود؛ یک شبیه ساز خانگی) به کمک SQL Server و فیلدهای XML آن طراحی شده است.
3) SQL Azure Federations
در اینجا منظور از Federations در حقیقت همان پیاده سازی قابلیت Sharding بانکهای اطلاعاتی NoSQL توسط SQL Azure است که برای توزیع اطلاعات بر روی سرورهای مختلف طراحی شده است. به این ترتیب دو قابلیت Partitioning و همچنین Replication به صورت خودکار در دسترس خواهند بود. هر Partition در اینجا، یک SQL Azure کامل است. بنابراین چندین بانک اطلاعاتی فیزیکی، یک بانک اطلاعاتی کلی را تشکیل خواهند داد.
هرچند در اینجا Sharding (که به آن Federation member گفته میشود) و در پی آن مفهوم «عاقبت یک دست شدن اطلاعات» وجود دارد، اما درون یک Shard یا یک Federation member، مفهوم ACID پیاده سازی شده است. از این جهت که هر Shard واقعا یک بانک اطلاعاتی رابطهای است. اینجا است که مفهوم برنامههای Multi-tenancy را برای درک آن باید درنظر داشت. برای نمونه یک برنامه وب را درنظر بگیرید که قسمت اصلی اطلاعات کاربران آن بر روی یک Shard قرار دارد و سایر اطلاعات بر روی سایر Shards پراکنده شدهاند. در این حالت است که یک برنامه وب با وجود مفهوم ACID در یک Shard میتواند سریع پاسخ دهد که آیا کاربری پیشتر در سایت ثبت نام کرده است یا خیر و از ثبت نامهای غیرمجاز جلوگیری به عمل آورد.
در اینجا تنها موردی که پشتیبانی نشدهاست، کوئریهای Fan-out میباشد که پیشتر در مورد آن بحث شد. از این جهت که با نحوه خاصی که Sharding آن طراحی شده است، نیازی به تهیه کوئریهایی که به صورت موازی بر روی کلیه Shards برای جمع آوری اطلاعات اجرا میشوند، نیست. هر چند از هر shard با استفاده از برنامههای دات نت، میتوان به صورت جداگانه نیز کوئری گرفت.
4) OData
اگر به CouchDB و امکان دسترسی به امکانات آن از طریق وب دقت کنید، در محصولات مایکروسافت نیز این دسترسی REST API پیاده سازی شدهاند.
OData یک RESTful API است برای دسترسی به اطلاعاتی که به شکل XML یا JSON بازگشت داده میشوند. انواع و اقسام کلاینتهایی برای کار با آن از جاوا اسکریپت گرفته تا سیستمهای موبایل، دات نت و جاوا، وجود دارند. از این API نه فقط برای خواندن اطلاعات، بلکه برای ثبت و به روز رسانی دادهها نیز استفاده میشود. در سیستمهای جاری مایکروسافت، بسیاری از فناوریها، اطلاعات خود را به صورت OData دراختیار مصرف کنندگان قرار میدهند مانند Azure table storage، کار با SQL Azure از طریق WCF Data Services (جایی که OData از آن نشات گرفته شده)، Azure Data Market (برای ارائه فیدهایی از اطلاعات خصوصا رایگان)، ابزارهای گزارشگیری مانند SQL Server reporting services، لیستهای شیرپوینت و غیره.
به این ترتیب به بسیاری از قابلیتهای دنیای NoSQL مانند کار با اطلاعات JSON بدون ترک دنیای رابطهای میتوان دسترسی داشت.
5) امکان اجرای MongoDB و امثال آن روی سکوی کاری Azure
امکان توزیع MongoDB بر روی یک Worker role سکوی کاری Azure وجود دارد. در این حالت بانکهای اطلاعاتی این سیستمها بر روی Azure Blob Storage قرار میگیرند که به آنها Azure drive نیز گفته میشود. همین روش برای سایر بانکهای اطلاعاتی NoSQL نیز قابل اجرا است.
به علاوه امکان اجرای Hadoop نیز بر روی Azure وجود دارد. مایکروسافت به کمک شرکتی به نام HortonWorks نسخه ویندوزی Hadoop را توسعه دادهاند. HortonWorks را افرادی تشکیل دادهاند که پیشتر در شرکت یاهو بر روی پروژه Hadoop کار میکردهاند.
6) قابلیتهای فرا رابطهای SQL Server
الف) فیلدهای XML (که در ابتدای این مطلب به آن پرداخته شد). به این ترتیب میتوان به یک اسکیمای انعطاف پذیر، بدون از دست دادن ضمانت ACID رسید.
ب) فیلد HierarchyId برای ذخیره سازی اطلاعات چند سطحی. برای مثال در بانکهای اطلاعاتی NoSQL سندگرا، یک سند میتواند سند دیگری را در خود ذخیره کند و الی آخر.
ج) Sparse columns؛ ستونهای اسپارس تقریبا شبیه به Key-value stores عمل میکنند و یا حتی Wide column stores نیز با آن قابل مقایسه است. در اینجا هنوز اسکیما وجود دارد، اما برای نمونه علت استفاده از Wide column stores این نیست که واقعا نمیدانید ساختار دادههای مورد استفاده چیست، بلکه در این حالت میدانیم که در هر ردیف تنها از تعداد معدودی از فیلدها استفاده خواهیم کرد. به همین جهت در هر ردیف تمام فیلدها قرار نمیگیرند، چون در اینصورت تعدادی از آنها همواره خالی باقی میماندند. مایکروسافت این مشکل را با ستونهای اسپارس حل کرده است؛ در اینجا هر چند ساختار کلی مشخص است، اما مواردی که هر بار استفاده میشوند، تعداد محدودی میباشند. به این صورت SQL Server تنها برای ستونهای دارای مقدار، فضایی را اختصاص میدهد. به این ترتیب از لحاظ فیزیکی و ذخیره سازی نهایی، به همان مزیت Wide column stores خواهیم رسید.
د) FileStreams در اس کیوال سرور بسیار شبیه به پیوستهای سندهای بانکهای اطلاعاتی NoSQL سندگرا هستند. در اینجا نیز اطلاعات در فایل سیستم ذخیره میشوند اما ارجاعی به آنها در جداول مرتبط وجود خواهند داشت.
7) SQL Server Parallel Data Warehouse Edition
SQL PDW، نگارش خاصی از SQL Server است که در آن یک شبکه از SQL Serverها به صورت یک وهله منطقی SQL Server در اختیار برنامه نویسها قرار میگیرد.
این نگارش، از فناوری خاصی به نام MPP یا massively parallel processing برای پردازش کوئریها استفاده میکند. در اینجا همانند بانکهای اطلاعاتی NoSQL، یک کوئری به نود اصلی ارسال شده و به صورت موازی بر روی تمام نودها پردازش گردیده (همان مفهوم Map Reduce که پیشتر در مورد آن بحث شد) و نتیجه در اختیار مصرف کننده قرار خواهد گرفت. نکته مهم آن نیز در عدم نیاز به نوشتن کدی جهت رخ دادن این عملیات از طرف برنامه نویسها است و موتور پردازشی آن جزئی از سیستم اصلی است. تنها کافی است یک کوئری SQL صادر گردد تا نتیجه نهایی از تمام سرورها جمع آوری و بازگردانده شود.
این نگارش ویژه تنها به صورت یک Appliance به فروش میرسد (به صورت سخت افزار و نرم افزار باهم) که در آن CPUها، فضاهای ذخیره سازی اطلاعات و جزئیات شبکه به دقت از پیش تنظیم شدهاند.
ASP.NET Web API فریم ورکی برای ساختن APIهای وب بر روی فریم ورک دات نت است. در این مقاله با استفاده از این فریم ورک، API وبی خواهیم ساخت که لیستی از محصولات را بر میگرداند. صفحه وب کلاینت، با استفاده از jQuery نتایج را نمایش خواهد داد.
یک پروژه Web API بسازید
در ویژوال استودیو 2013 پروژه جدیدی از نوع ASP.NET Web Application بسازید و نام آن را "ProductsApp" انتخاب کنید.
در دیالوگ New ASP.NET Project قالب Empty را انتخاب کنید و در قسمت "Add folders and core references for" گزینه Web API را انتخاب نمایید.
می توانید از قالب Web API هم استفاده کنید. این قالب با استفاده از ASP.NET MVC صفحات راهنمای API را خواهد ساخت. در این مقاله از قالب Empty استفاده میکنیم تا تمرکز اصلی، روی خود فریم ورک Web API باشد. بطور کلی برای استفاده از این فریم ورک لازم نیست با ASP.NET MVC آشنایی داشته باشید.
افزودن یک مدل
یک مدل (model) آبجکتی است که داده اپلیکیشن شما را معرفی میکند. ASP.NET Web API میتواند بصورت خودکار مدل شما را به JSON, XML و برخی فرمتهای دیگر مرتب (serialize) کند، و سپس داده مرتب شده را در بدنه پیام HTTP Response بنویسد. تا وقتی که یک کلاینت بتواند فرمت مرتب سازی دادهها را بخواند، میتواند آبجکت شما را deserialize کند. اکثر کلاینتها میتوانند XML یا JSON را تفسیر کنند. بعلاوه کلاینتها میتوانند فرمت مورد نظرشان را با تنظیم Accept header در پیام HTTP Request مشخص کنند.
بگذارید تا با ساختن مدلی ساده که یک محصول (product) را معرفی میکند شروع کنیم.
کلاس جدیدی در پوشه Models ایجاد کنید.
نام کلاس را به "Product" تغییر دهید، و خواص زیر را به آن اضافه کنید.
namespace ProductsApp.Models { public class Product { public int Id { get; set; } public string Name { get; set; } public string Category { get; set; } public decimal Price { get; set; } } }
افزودن یک کنترلر
در Web API کنترلرها آبجکت هایی هستند که درخواستهای HTTP را مدیریت کرده و آنها را به اکشن متدها نگاشت میکنند. ما کنترلری خواهیم ساخت که میتواند لیستی از محصولات، یا محصولی بخصوص را بر اساس شناسه برگرداند. اگر از ASP.NET MVC استفاده کرده اید، با کنترلرها آشنا هستید. کنترلرهای Web API مشابه کنترلرهای MVC هستند، با این تفاوت که بجای ارث بری از کلاس Controller از کلاس ApiController مشتق میشوند.
کنترلر جدیدی در پوشه Controllers ایجاد کنید.
در دیالوگ Add Scaffold گزینه Web API Controller - Empty را انتخاب کرده و روی Add کلیک کنید.
در دیالوگ Add Controller نام کنترلر را به "ProductsController" تغییر دهید و روی Add کلیک کنید.
توجه کنید که ملزم به ساختن کنترلرهای خود در پوشه Controllers نیستید، و این روش صرفا قراردادی برای مرتب نگاه داشتن ساختار پروژهها است. کنترلر ساخته شده را باز کنید و کد زیر را به آن اضافه نمایید.
using ProductsApp.Models; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Web.Http; namespace ProductsApp.Controllers { public class ProductsController : ApiController { Product[] products = new Product[] { new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 }, new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M }, new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M } }; public IEnumerable<Product> GetAllProducts() { return products; } public IHttpActionResult GetProduct(int id) { var product = products.FirstOrDefault((p) => p.Id == id); if (product == null) { return NotFound(); } return Ok(product); } }
کنترلر ما دو متد برای دریافت محصولات تعریف میکند:
- متد GetAllProducts لیست تمام محصولات را در قالب یک <IEnumerable<Product بر میگرداند.
- متد GetProductById سعی میکند محصولی را بر اساس شناسه تعیین شده پیدا کند.
همین! حالا یک Web API ساده دارید. هر یک از متدهای این کنترلر، به یک یا چند URI پاسخ میدهند:
URI | Controller Method |
api/products/ | GetAllProducts |
api/products/id/ | GetProductById |
برای اطلاعات بیشتر درباره نحوه نگاشت درخواستهای HTTP به اکشن متدها توسط Web API به این لینک مراجعه کنید.
فراخوانی Web API با جاوا اسکریپت و jQuery
در این قسمت یک صفحه HTML خواهیم ساخت که با استفاده از AJAX متدهای Web API را فراخوانی میکند. برای ارسال درخواستهای آژاکسی و بروز رسانی صفحه بمنظور نمایش نتایج دریافتی از jQuery استفاده میکنیم.
در پنجره Solution Explorer روی نام پروژه کلیک راست کرده و گزینه Add, New Item را انتخاب کنید.
در دیالوگ Add New Item قالب HTML Page را انتخاب کنید و نام فایل را به "index.html" تغییر دهید.
حال محتوای این فایل را با لیست زیر جایگزین کنید.
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Product App</title> </head> <body> <div> <h2>All Products</h2> <ul id="products" /> </div> <div> <h2>Search by ID</h2> <input type="text" id="prodId" size="5" /> <input type="button" value="Search" onclick="find();" /> <p id="product" /> </div> <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.0.3.min.js"></script> <script> var uri = 'api/products'; $(document).ready(function () { // Send an AJAX request $.getJSON(uri) .done(function (data) { // On success, 'data' contains a list of products. $.each(data, function (key, item) { // Add a list item for the product. $('<li>', { text: formatItem(item) }).appendTo($('#products')); }); }); }); function formatItem(item) { return item.Name + ': $' + item.Price; } function find() { var id = $('#prodId').val(); $.getJSON(uri + '/' + id) .done(function (data) { $('#product').text(formatItem(data)); }) .fail(function (jqXHR, textStatus, err) { $('#product').text('Error: ' + err); }); } </script> </body> </html>
گرفتن لیستی از محصولات
برای گرفتن لیستی از محصولات، یک درخواست HTTP GET به آدرس "api/products/" ارسال کنید.
تابع getJSON یک درخواست آژاکسی ارسال میکند. پاسخ دریافتی هم آرایه ای از آبجکتهای JSON خواهد بود. تابع done در صورت موفقیت آمیز بودن درخواست، اجرا میشود. که در این صورت ما DOM را با اطلاعات محصولات بروز رسانی میکنیم.
$(document).ready(function () { // Send an AJAX request $.getJSON(apiUrl) .done(function (data) { // On success, 'data' contains a list of products. $.each(data, function (key, item) { // Add a list item for the product. $('<li>', { text: formatItem(item) }).appendTo($('#products')); }); }); });
گرفتن محصولی مشخص
برای گرفتن یک محصول توسط شناسه (ID) آن کافی است یک درخواست HTTP GET به آدرس "api/products/id/" ارسال کنید.
function find() { var id = $('#prodId').val(); $.getJSON(apiUrl + '/' + id) .done(function (data) { $('#product').text(formatItem(data)); }) .fail(function (jqXHR, textStatus, err) { $('#product').text('Error: ' + err); }); }
اجرای اپلیکیشن
اپلیکیشن را با F5 اجرا کنید. صفحه وب باز شده باید چیزی مشابه تصویر زیر باشد.
برای گرفتن محصولی مشخص، شناسه آن را وارد کنید و روی Search کلیک کنید.
اگر شناسه نامعتبری وارد کنید، سرور یک خطای HTTP بر میگرداند.
استفاده از F12 برای مشاهده درخواستها و پاسخ ها
هنگام کار با سرویسهای HTTP، مشاهدهی درخواستهای ارسال شده و پاسخهای دریافتی بسیار مفید است. برای اینکار میتوانید از ابزار توسعه دهندگان وب استفاده کنید، که اکثر مرورگرهای مدرن، پیاده سازی خودشان را دارند. در اینترنت اکسپلورر میتوانید با F12 به این ابزار دسترسی پیدا کنید. به برگه Network بروید و روی Start Capturing کلیک کنید. حالا صفحه وب را مجددا بارگذاری (reload) کنید. در این مرحله اینترنت اکسپلورر ترافیک HTTP بین مرورگر و سرور را تسخیر میکند. میتوانید تمام ترافیک HTTP روی صفحه جاری را مشاهده کنید.
به دنبال آدرس نسبی "api/products/" بگردید و آن را انتخاب کنید. سپس روی Go to detailed view کلیک کنید تا جزئیات ترافیک را مشاهده کنید. در نمای جزئیات، میتوانید headerها و بدنه درخواستها و پاسخها را ببینید. مثلا اگر روی برگه Request headers کلیک کنید، خواهید دید که اپلیکیشن ما در Accept header دادهها را با فرمت "application/json" درخواست کرده است.
اگر روی برگه Response body کلیک کنید، میتوانید ببینید چگونه لیست محصولات با فرمت JSON سریال شده است. همانطور که گفته شده مرورگرهای دیگر هم قابلیتهای مشابهی دارند. یک ابزار مفید دیگر Fiddler است. با استفاده از این ابزار میتوانید تمام ترافیک HTTP خود را مانیتور کرده، و همچنین درخواستهای جدیدی بسازید که این امر کنترل کاملی روی HTTP headers به شما میدهد.
قدمهای بعدی
سایت MS-DEV متشکل است از یک سری دوره آموزشی مباحث مختلف مانند XAML ، سیلورلایت، WPF ، SQL Server 2008 ، windows server 2008 و غیره.
لیست کامل این دورهها به همراه آدرسهای ویدیوهای رایگان مرتبط را از آدرس زیر میتوانید دریافت کنید:
تعاریف مداخل فایل index.html یک سایت AngularJS 2.0
پروژهای که در اینجا در حال استفاده است یک برنامهی ASP.NET MVC 5.x است؛ اما الزامی هم به استفادهی از آن وجود ندارد. یا یک فایل index.html را به ریشهی پروژه اضافه کنید و یا فایل Views\Shared\_Layout.cshtml را به نحو ذیل تغییر دهید:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>@ViewBag.Title - My ASP.NET Application</title> <link href="~/node_modules/bootstrap/dist/css/bootstrap.css" rel="stylesheet" /> <link href="~/app/app.component.css" rel="stylesheet"/> <link href="~/Content/Site.css" rel="stylesheet" type="text/css" /> <!-- 1. Load libraries --> <!-- IE required polyfills, in this exact order --> <script src="~/node_modules/angular2/es6/dev/src/testing/shims_for_IE.js"></script> <script src="~/node_modules/es6-shim/es6-shim.min.js"></script> <script src="~/node_modules/systemjs/dist/system-polyfills.js"></script> <script src="~/node_modules/angular2/bundles/angular2-polyfills.js"></script> <script src="~/node_modules/systemjs/dist/system.src.js"></script> <script src="~/node_modules/rxjs/bundles/Rx.js"></script> <script src="~/node_modules/angular2/bundles/angular2.dev.js"></script> <!-- Required for http --> <script src="~/node_modules/angular2/bundles/http.dev.js"></script> <!-- Required for routing --> <script src="~/node_modules/angular2/bundles/router.dev.js"></script> <!-- 2. Configure SystemJS --> <script> System.config({ packages: { app: { format: 'register', defaultExtension: 'js' } } }); System.import('app/main') .then(null, console.error.bind(console)); </script> </head> <body> <div> @RenderBody() <pm-app>Loading App...</pm-app> </div> @RenderSection("Scripts", required: false) </body> </html>
سپس کتابخانههای جاوا اسکریپتی مورد نیاز جهت کار با AngularJS 2.0 به ترتیبی که ذکر شده، باید تعریف شوند.
ذکر /~ در ابتدای آدرسها، مختص به ASP.NET MVC است. اگر از آن استفاده نمیکنید، نیازی به ذکر آن هم نیست.
در ادامه تعاریف System.JS ذکر شدهاست. System.JS کار بارگذاری ماژولهای برنامه را به عهده دارد. به این ترتیب دیگر نیازی نیست تا به ازای هر قسمت جدید برنامه، مدخلی را در اینجا اضافه کرد و کار بارگذاری آنها خودکار خواهد بود. فرمت register ایی که در اینجا ذکر شدهاست، تا ماژولهای استاندارد با فرمت ES 6 را نیز پشتیبانی میکند. همچنین با ذکر و تنظیم پسوند پیش فرض به js، دیگر نیازی نخواهد بود تا در حین تعریف importها در قسمتهای مختلف برنامه، پسوند فایلها را به صورت صریح ذکر کرد. مبحث improtها مرتبط است به مفاهیم ماژولها در ES 6 و همچنین TypeScript.
سطر System.import کار بارگذاری اولین ماژول برنامه را از پوشهی app قرار گرفته در ریشهی سایت انجام میدهد. این ماژول main نام دارد.
نوشتن اولین کامپوننت AngularJS 2.0
برنامههای AngularJS 2.0 متشکل هستند از تعدادی کامپوننت و سرویس:
و هر کامپوننت تشکیل شدهاست از:
- یک قالب یا Template: با استفاده از HTML تعریف میشود و کار تشکیل View و نحوهی رندر کامپوننت را مشخص میکند. در این Viewها با استفاده از امکانات binding و directives موجود در AngularJS 2.0 کار دسترسی به دادهها صورت میگیرد.
- یک کلاس: کار این کلاس که توسط TypeScript تهیه میشود، فراهم آوردن کدهای مرتبط با قالب است. برای مثال این کلاس حاوی تعدادی خاصیت خواهد بود که از اطلاعات آنها در View مرتبط استفاده میشود. همچنین این کلاس میتواند حاوی متدهای مورد نیاز در View نیز باشد؛ برای مثال متدی که کار نمایش یا مخفی سازی یک تصویر را با کلیک بر روی دکمهای انجام میدهد.
- متادیتا: متادیتا (یا decorator در اینجا) به AngularJS 2.0 اعلام میکند که این کلاس تعریف شده، صرفا یک کلاس ساده نیست و باید به آن به صورت یک کامپوننت نگاه شود.
در ذیل، کدهای یک کامپوننت نمونهی AngularJS 2.0 را مشاهده میکنید:
import { Component } from 'angular2/core'; @Component({ selector: 'pm-app', template:` <div><h1>{{pageTitle}}</h1> <div>My First Component</div> </div> ` }) export class AppComponent { pageTitle: string = "DNT AngularJS 2.0 APP"; }
بلافاصله در بالای این کلاس، متد decorator ایی را به نام Component مشاهده میکنید. این متادیتا است که به AngularJS 2.0 اعلام میکند، کلاس AppComponent تعریف شده، یک کامپوننت است و نه تنها یک کلاس ساده.
در متد Component تعریف شده، قالب یا template نحوهی رندر این کامپوننت را مشاهده میکنید.
در ابتدای این ماژول نیز کار import تعاریف مرتبط با متد ویژهی Component، از هستهی AngularJS 2.0 انجام شدهاست تا کامپایلر TypeScript بتواند این فایل ts را کامپایل کند.
مروری بر نحوهی تعریف class در TypeScript
مرور جامع کلاسها در TypeScript را در مطلب «مبانی TypeScript؛ کلاسها» میتوانید مطالعه کنید. در اینجا جهت یادآوری، خلاصهای از آنرا که نیاز داریم، بررسی خواهیم کرد:
- جهت تعریف یک کلاس، ابتدا واژهی کلیدی class به همراه نام کلاس ذکر میشوند.
- در AngularJS 2.0 مرسوم است که نام کلاس را به صورت نام ویژگی مدنظر به همراه پسوند Component ذکر کنیم؛ مانند AppComponent مثال فوق. این نام pascal case است و با حروف بزرگ شروع میشود.
- همچنین مرسوم است در برنامههای AngularJS 2.0، کامپوننت ریشهی سایت نیز AppComponent نامیده شود.
- در مثال فوق، واژهی کلیدی export را نیز پیش از واژهی کلیدی class مشاهده میکنید. به این ترتیب این کلاس خارج از ماژولی که در آن تعریف میشود، قابل دسترسی خواهد بود. اکنون این کلاس و فایل، تبدیل به ماژولی خواهند شد که توسط module loader معرفی شدهی در ابتدای بحث یا همان System.JS به صورت خودکار بارگذاری میشود و دیگر نیازی به تعریف مدخل script متناظر با آن در فایل index.html نخواهد بود.
- در بدنهی کلاس، کار تعریف متدها و خواص مورد نیاز View صورت میگیرند. برای نمونه در اینجا تنها یک خاصیت «عنوان صفحه» تعریف شدهاست. در جاوا اسکریپت مرسوم است که نام خواص را camel case شروع شده با حروف کوچک تعریف کنیم. سپس نوع این خاصیت به صورت رشتهای تعریف شدهاست و در آخر مقدار پیش فرض این خاصیت ذکر گردیدهاست.
البته باید دقت داشت که الزامی به ذکر نوع خاصیت، در TypeScript وجود ندارد. همینقدر که مقدار پیش فرض این خاصیت رشتهای است، بر اساس ویژگی به نام Type inference در TypeScript، نوع این خاصیت نیز رشتهای درنظر گرفته خواهد شد و دیگر نمیتوان برای مثال یک عدد را به آن انتساب داد.
- سطح دسترسی خواص تعریف شدهی در یک کلاس TypeScript به صورت پیش فرض public است. بنابراین در اینجا نیازی به ذکر صریح آن نبودهاست.
مروری بر متادیتا یا decorator یک کلاس در AngularJS 2.0
خوب، تا اینجا کلاس AppComponent تعریف و همچنین export شد تا توسط system.js به صورت خودکار بارگذاری شود. اما این کلاس به خودی خود صرفا یک کلاس TypeScript ایی است و توسط AngularJS شناسایی نمیشود. برای معرفی این کلاس به صورت یک کامپوننت، از یک تزئین کننده یا decorator ویژه به نام Component استفاده میشود که بلافاصله در بالای تعریف کلاس قرار میگیرد؛ چیزی شبیه به data annotations یا attributes در زبان #C.
یک decorator متدی است که اطلاعاتی اضافی را به یک کلاس، اعضاء و متدهای آن و یا حتی آرگومانهای آن متدها، الصاق میکند. این ویژگی قرار است به صورت استاندارد در ES 2016 یا نگارش بعدی جاوا اسکریپت حضور داشته باشد و در حال حاضر توسط TypeScript پشتیبانی شده و در نهایت به کدهای ES 5 قابل اجرای در تمام مرورگرها ترجمه میشود.
یک decorator همیشه با @ شروع میشود و AngularJS 2.0 به همراه تعدادی decorator توکار است؛ مانند Component. از آنجائیکه decorator یک متد است، همیشه به همراه یک جفت پرانتز () ذکر میشود و در انتهای آن نیازی به ذکر سمیکالن نیست. در اینجا تزئین کنندهی Component یک شیء را میپذیر که به همراه تعدادی خاصیت است. به همین جهت پارامتر آن به صورت {} ذکر شدهاست.
خاصیت selector یک کامپوننت مشخص میکند که نام directive متناظر با این کامپوننت چیست:
selector: 'pm-app',
<div> @RenderBody() <pm-app>Loading App...</pm-app> </div>
template:` <div><h1>{{pageTitle}}</h1> <div>My First Component</div> </div> `
همچنین {{}} به معنای تعریف data binding است. به این ترتیب مقداری که قرار است به صورت تگ h1 رندر شود، از خاصیت pageTitle کلاس مزین شدهی توسط این ویژگی یا decorator تامین خواهد شد؛ یعنی مقدار پیش فرض خاصیت pageTitle در کلاس AppComponent.
import اطلاعات مورد نیاز جهت کامپایل یک فایل TypeScript
تا اینجا مفاهیم موجود در کلاس AppComponent را به همراه متادیتای آن بررسی کردیم. اما این متادیتای جدید کامپوننت، به صورت پیش فرض ناشناختهاست:
همانطور که مشاهده میکنید، در اینجا ذیل کامپوننت، خط قرمزی جهت یادآوری عدم تعریف آن، کشیده شدهاست. در TypeScript و یا ES 6، پیش از استفاده از یک کلاس یا متد خارجی، نیاز است به module loader اعلام کنیم تا آنرا باید از کجا تامین کند. اینکار توسط عبارت import انجام میشود که شبیه به عبارت using در زبان سیشارپ است. عبارت import جزئی از استاندارد ES 6 است و همچنین در TypeScript نیز پشتیبانی میشود. به این ترتیب امکان دسترسی به ویژگیهای export شدهی از سایر ماژولها را در ماژول فعلی (فایل فعلی در حال کار) خواهیم یافت. نمونهی آنرا با ذکر واژهی کلیدی export پیش از کلاس AppComponent پیشتر ملاحظه کردید.
این ماژولهای خارجی میتوانند سایر ماژولها و فایلهای ts نوشته شدهی توسط خودمان و یا حتی اجزای AngularJS 2.0 باشند. طراحی AngularJS 2.0 نیز ماژولار است و از ماژولهایی مانند angular2/core، angular2/animation، angular2/http و angular2/router تشکیل شدهاست.
برای نمونه متادیتای کامپوننت، در ماژول angular2/core قرار دارد. به همین جهت نیاز است در ابتدای ماژول فعلی آنرا import کرد:
import { Component } from 'angular2/core';
ساخت کامپوننت ریشهی یک برنامهی AngularJS 2.0
در ابتدای بحث که تعاریف مداخل مورد نیاز جهت اجرای یک برنامهی AngularJS 2.0 ذکر شدند، عنوان شد که system.js به دنبال ماژول آغازین app/main میگردد.
بنابراین در ریشهی پروژه، پوشهی جدیدی را به نام app ایجاد کنید.
سپس یک فایل TypeScript جدید را به نام app.component.ts به این پوشه اضافه کنید. قالب این نوع فایلها در add new item و با جستجو typescript در دسترس است و یا حتی یک فایل متنی ساده را هم با پسوند ts ایجاد کنید، کافی است.
نامگذاری این فایلها هم مرسوم است به صورت ذکر نام ویژگی به همراه یک دات و سپس ذکر کامپوننت صورت گیرد. در اینجا چون قصد داریم کامپوننت ریشهی برنامه را ایجاد کنیم، نام ویژگی آن app خواهد بود و نام کامل فایل به این ترتیب app.component.ts میشود.
سپس محتوای این فایل را به دقیقا معادل کدهای قسمت «نوشتن اولین کامپوننت AngularJS 2.0» ابتدای بحث تغییر دهید (همان import، متادیتا و کلاس AppComponent).
تا اینجا کامپوننت ریشهی برنامه ایجاد شد. اما چگونه باید از آن استفاده کنیم و چگونه AngularJS 2.0 آنرا شناسایی میکند؟ به این فرآیند آغازین شناسایی و بارگذاری ماژولها، اصطلاحا bootstrapping میگویند. تنها صفحهی واقعی موجود در یک برنامهی تک صفحهای وب، همان فایل index.html است و سایر صفحات و محتوای آنها به محتوای این صفحهی آغازین اضافه یا کم خواهند شد.
<div> @RenderBody() <pm-app>Loading App...</pm-app> </div>
خوب، اکنون module loader یا system.js چگونه این pm-app یا کامپوننت ریشهی برنامه را شناسایی میکند؟
System.import('app/main')
/// <reference path="../node_modules/angular2/typings/browser.d.ts" /> import { bootstrap } from "angular2/platform/browser"; // Our main component import { AppComponent } from "./app.component"; bootstrap(AppComponent);
در انتهای این فایل متد bootstrap مربوط به AngularJS 2.0 را مشاهده میکنید. کار آن بارگذاری اولین ماژول و کامپوننت برنامه یا همان AppComponent است.
در ادامه نیاز است AppComponent را به این ماژول معرفی کرد؛ در غیراینصورت کامپایل نخواهد شد. برای این منظور سطر import این کلاس را از فایل app.component، مشاهده میکنید. در اینجا نیازی به ذکر پسوند ts. فایل app.component نیست.
سپس نیاز است محل تعریف متد بوت استرپ را نیز مشخص کنیم. این متد در ماژول angular2/platform/browser قرار دارد که به عنوان اولین import این فایل ذکر شدهاست.
سطر اول، مربوط است به تعریف فایلهای d.ts. مربوط به TypeScript جهت شناسایی نوعهای مرتبط با AngularJS 2.0. اگر اینکار صورت نگیرد، خطاهای ذیل را در حین کامپایل فایلهای TypeScript دریافت خواهید کرد:
node_modules\angular2\src\core\application_ref.d.ts(171,81): error TS2304: Build: Cannot find name 'Promise'. node_modules\angular2\src\core\change_detection\differs\default_keyvalue_differ.d.ts(23,15): error TS2304: Build: Cannot find name 'Map'.
تا اینجا پوشهی app واقع در ریشهی سایت، یک چنین شکلی را پیدا میکند:
و اکنون اگر برنامه را اجرا کنیم (فشردن دکمهی F5)، خروجی آن در مرورگر به صورت ذیل خواهد بود:
با توجه به اینکه در حال کار با یک برنامهی جاوا اسکریپتی هستیم، باز نگه داشتن developer tools مرورگر، جهت مشاهدهی خطاهای احتمالی ضروری است.
در اینجا اگر خطایی وجود داشته باشد، یا اطلاعات اضافی مدنظر باشد، در console لاگ خواهند شد. برای مثال در اینجا عنوان شدهاست که برنامه در حالت توسعه در حال اجرا است. بهتر است برای ارائهی نهایی، متد enableProdMode را در فایل index.html فراخوانی کنید.
همچنین در اینجا میتوان HTML نهایی تزریق شدهی به صفحه را بهتر مشاهده کرد:
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: MVC5Angular2.part2.zip
برای اجرای آن، ابتدا به فایل project.json مراجعه کرده و یکبار آنرا ذخیره کنید تا وابستگیهای اسکریپتی پروژه از اینترنت دریافت شوند (این موارد در قسمت قبل مرور شدند). سپس یکبار هم پروژه را Build کنید تا تمام فایلهای ts آن کامپایل شوند و در آخر، اجرای نهایی پروژه.
خلاصهی بحث
یک برنامهی AngularJS 2.0 متشکل است از تعدادی کامپوننت. بنابراین کلاسی را ایجاد خواهیم کرد تا کدهای پشتیبانی کنندهی View این کامپوننت را تولید کند. سپس این کلاس را با متادیتایی مزین کرده و توسط آن تگ سفارشی ویژهی این کامپوننت و تگهای HTML تشکیل دهندهی این کامپوننت را به AngularJS 2.0 معرفی میکنیم. در اینجا در صورت نیاز وابستگیهای تعریف این متادیتا را توسط واژهی کلیدی import دریافت میکنیم. نام این کلاس بهتر است Pascal case بوده و با حروف بزرگ شروع شود و همچنین به صورت نام ویژگی ختم شدهی به کلمهی Component باشد. در اینجا حتما نیاز است این کلاس export شود تا توسط module loader قابل استفاده و بارگذاری گردد. اگر View این کامپوننت نیاز به دریافت اطلاعاتی دارد، این اطلاعات به صورت خواصی در کلاس کامپوننت تعریف میشوند. این خواص تعریف شدهی با سطح دسترسی عمومی، مرسوم است به صورت camel case تعریف شوند و حروف اول آنها کوچک باشد.
public class AccessControlService { private DbContext db; public AccessControlService() { db = new DbContext(); } public IEnumerable<Permission> GetUserPermissions(string userId) { var userRoles = this.GetUserRoles(userId); var userPermissions = new List<Permission>(); foreach (var userRole in userRoles) { foreach (var permission in userRole.Permissions) { // prevent duplicates if (!userPermissions.Contains(permission)) userPermissions.Add(permission); } } return userPermissions; } public IEnumerable<Role> GetUserRoles(string userId) { return db.Users.FirstOrDefault(x => x.UserId == userId).Roles.ToList(); } public bool HasPermission(string userId, string area, string control) { var found = false; var userPermissions = this.GetUserPermissions(userId); var permission = userPermissions.FirstOrDefault(x => x.Area == area && x.Control == control); if (permission != null) found = true; return found; } {
[RoutePrefix("َAuth/permissions")] public class PermissionsController : ApiController { private AccessControlService _AccessControlService = null; public PermissionsController() { _AccessControlService = new AccessControlService(); } [Route("GetUserPermissions")] public async Task<IHttpActionResult> GetUserPermissions() { if (!User.Identity.IsAuthenticated) { return Unauthorized(); } return Ok(_AccessControlService.GetPermissions(User.Identity.GetCurrentUserId())); } }
توسعه سرویسها و فرآیندهای سمت وب کلاینت AngularJS
'use strict'; angular.module('App').factory('permissionService', ['$http', '$q', function ($http, $q) { var _getUserPermissions = function () { return $http.get(serviceBaseUrl + '/api/permissions/GetUserPermissions/'); } var _isAuthorize = function (area, control) { return _.some($scope.permissions, { 'area': area, 'control': control }); } return { getUserPermissions: _getUserPermissions, isAuthorize: _isAuthorize }; }]);
$scope.login = function () { authService.login($scope.loginData).then(function (response) { savePermissions(); $location.path('/userPanel'); }, function (err) { $scope.message = err.error_description; }); }; var savePermissions = function () { permissionService.getUserPermissions().then(function (response) { $rootScope.permissions = response.data; }, function (err) { }); } }
App.controller('parentController', ['$rootScope', '$scope', 'authService', 'permissionService', function ($rootScope, $scope, authService, permissionService) { $scope.authentication = authService.authentication; // isAuthorize Method $scope.isAuthorize = permissionService.isAuthorize(); // rest of codes }]);
<div ng-controller="childController"> <div ng-if="isAuthorize('articles', 'edit')" > <!-- the block that we want to not see unauthorize person --> </div> </div>