در تصویر بالا دو مسیر با آدرسهای : ShowPage1/ و ShowPage2/ تعریف شده است که هر کدام به یک view مشخص و یک Controller برای مدیریت آن اشاره میکند.
زمانی که ما از تزریق وابستگیها در AngularJs استفاده میکنیم و یک شیء را به کنترلر تزریق میکنیم، Angular توسط Injector$ سعی در پیدا کردن وابستگی مربوطه و سپس تزریق آن به کنترلر را انجام میدهد. برای استفاده از امکان مسیریابی Route ، ما نیز باید از پروایدر مخصوص آن برای تزریق استفاده کنیم. در Angular مسیرهای برنامه توسط پروایدری به نام routeProvider$ شناسایی میشود که خدمات مسیریابی را به ما ارائه میدهد. این سرویس به ما کمک میکند تا بتوانیم اتصال بین کنترلر ها، ویوها و آدرس URL جاری مرورگرها را به آسانی برقرار کنیم.
بهتر است کار را شروع کنیم . یک فایل JS ایجاد و سپس محتویات زیر را در آن قرار دهید :
var myFirstRoute = angular.module('myFirstRoute', []); myFirstRoute.config(['$routeProvider', function($routeProvider) { $routeProvider. when('/pageOne', { templateUrl: 'templates/page_one.html', controller: 'ShowPage1Controller' }). when('/pageTwo', { templateUrl: 'templates/page_two.html', controller: 'ShowPage2Controller' }). otherwise({ redirectTo: '/pageOne' }); }]); myFirstRoute.controller('ShowPage1Controller', function($scope) { $scope.message = 'Content of page-one.html'; }); myFirstRoute.controller('ShowPage2Controller', function($scope) { $scope.message = 'Content of page-two.html'; });
در کدهای بالا ابتدا یک ماژول تعریف کرده ایم و سپس توسط ()config. تنظیمات مربوط به مسیریابی را انجام داده ایم. با استفاده از متدهای when. و otherwise. میتوانیم مسیرها را تعریف کنیم. برای هر مسیر دو پارامتر وجود دارد که اولین پارامتر نام مسیر و دومین پارامتر شامل 2 قسمت میشود که templateUrl آن آدرسی که باز خواهد شد و controller نیز نام کنترلری که ویو را مدیریت میکند.
توسط otherwise میتوانیم مسیر پیشفرض را نیز تعریف کنیم تا درصورتی که مسیری با آدرسهای بالای آن مطابقت نداشت به این آدرس منتقل شود.
در قطعه کد بالا همچنین دو مسیر با نامهای pageOne/ و pageTwo/ تعریف کرده ایم که هر کدام به ترتیب به Viewهای : templates/page_one.html و templates/page_two.html مرتبط شده اند. همچنین دو کنترلر برای مدیریت ویوها نیز تعریف شده است.
زمانی که ما آدرس http://appname/#pageOne را در نوار آدرس مرورگر وارد میکنیم، Angular به صورت اتوماتیک آدرس URL را با تنظیماتی که ما در اینجا تعریف کرده ایم مطابقت میدهد و در صورت وجود چنین آدرسی ، view مربوطه را بارگزاری میکند و در این مثال نیز مطابق با تنظیمات بالا، صفحهی templates/page_one.html برای ما بارگزاری و سپس کنترلر ShowPage1Controller را فراخوانی میکند ، جایی که ما منطق کار را در آن قرار میدهیم.
محتویات فایل main.html :
<body ng-app="app"> <div> <div> <div> <ul> <li><a href="#pageOne"> Show page one </a></li> <li><a href="#pageTwo"> Show page two </a></li> </ul> </div> <div> <div ng-view></div> </div> </div> </div> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> <script src="app.js"></script> </body>
در قطعه کد بالا دو لینک تعریف شده است که ویژگی href از علامت هش و نام صفحه تشکیل شده است. یکی از چیزهایی که شایان ذکر است ، دایرکتیو ng-view است. مکانی برای بارگزاری صفحات در آن.
ما میتوانیم این تگ را به سه شکل زیر نیز استفاده کنیم :
<div ng-view></div> .. <ng-view></ng-view> .. <div class="ng-view"></div>
محتویات صفحه templates/page_one.html :
<h2>Page One</h2> {{ message }}
محتویات صفحه templates/page_two.html :
<h2>Page Two</h2> {{ message }}
حال اگر پروژه را اجرا کنید و به کنسول مرور گر خود نگاه کنید متوجه میشوید که مسیریاب از مسیر پیشفرض استفاده کرده است و صفحهی page_one.html را به صورت ایجکسی فراخوانی کرده است :
و اگر روی لینک Show Page two کلیک کنید ، صفحهی page_two.html نیز به صورت ایجکسی فراخوانی میشود.
دوباره بر روی لینک Show page one کلیک کنید. بله. هیچ درخواستی به سمت سرور ارسال نشد و صفحهی page_one.html به خوبی نمایش داده شد. یکی از مزیتهای سیستم مسیریابی قابلیت کش کردن صفحات است تا در صورت فراخوانی مجدد، درخواستی به سمت سرور ارسال نشود و خیلی سریع به شما نمایش داده شود.
مثال این مطلب : RouteExample.zip
ادامه دارد ...
در بخشهای پیشین ( بخش اول و بخش دوم) به خوبی با اصول و روش مسیریابی (Routing) در AngularJS آشناشدیم. در این بخش میخواهم به برخی جزئیات درباره مسیریابی بپردازم.اولین موضوع، تغییراتی است که از نسخه 1.2 به بعد در روش استفاده از سرویس مسیریابی در AngularJS بوجود آمده است. از نسخه 1.2 سرویس مسیریابی از هسته اصلی AngularJS خارج شد و برای استفاده از امکانات این سرویس باید فایل angular-route.js و یا angular-route.min.js را به صفحه خود بیفزاییم:
<script src="~/Scripts/angular.min.js"></script> <script src="~/Scripts/angular-route.min.js"></script>
var app = angular.module("mainApp", ['ngRoute']);
.when('/controllerAS', { controller: 'testController', controllerAs: 'tCtrl', template: '<div>{{tCtrl.Title}}</div>' })
when(string path, object route)
- routeParams$ برای دسترسی به پارامترهای آمده در آدرس صفحه جاری.
- ()location.path$ جاری به صورت یک رشته.
- ()location.search$ جاری به صورت یک شی.
.when('/controllerAS', { controller: 'testController', controllerAs: 'tCtrl', template: '<div>{{tCtrl.Title}}</div>', caseInsensitiveMatch: true })
$routeProvider .when('/resolveTest', { resolve: { // این وابستگی بلافاصله بازمیگردد person: function () { return { name: "Hamid Saberi", email: "Hamid.Saberi@Gmail.com" } }, // بازمیگرداند promise این وابستگی یک // شدن آن به تاخیر میافتد resolve پس تغییر مسیر تا currentDetails: function ($http) { return $http({ method: 'Get', url: '/current_details' }); }, //میتوانیم از یک وابستگی در وابستگی دیگر استفاده کنیم facebookId: function ($http, currentDetails) { $http({ method: 'GET', url: 'http://facebook.com/api/current_user', params: { email: currentDetails.data.emails[0] } }) }, // بارگذاری فایلهای اسکریپت مورد نیاز fileDeps:function($q, $rootScope){ var deferred = $q.defer(); var dependencies = [ 'controllers/AboutViewController.js', 'directives/some-directive.js' ]; //$Script.js بارگذاری وابستگیها با استفاده از $script(dependencies, function(){ // همه وابستگیها بارگذاری شده اند $rootScope.$apply(function(){ deferred.resolve(); }); }); return deferred.promise; } }, controller: function ($scope, person, currentDetails, facebookId) { this.Person = person; }, controllerAs: 'rtCtrl', template: '<div>{{rtCtrl.Person.name}}</div>', caseInsensitiveMatch: true })
Last week, at ng-conf, the Angular team at Google provided the web developer world with an update on the state of Angular 2. They were joined on stage by a member of the TypeScript team, Jonathan Turner, to also announce that Angular 2 will be built using TypeScript. Jonathan then demoed a preview of the upcoming TypeScript 1.5 release via an Angular 2 sample application.
قابلیت چند زبانه و Localization در AngularJs- بخش چهارم و نهایی: Best Practiceهای angular-translate
ex7_load_static_files
<script src="Scripts/angular.js"></script> <script src="Scripts/angular-cookies.js"></script> <script src="Scripts/angular-translate.js"></script> <script src="Scripts/angular-translate-storage-cookie.js"></script> <!-- for override loader methods in angular translate --> <script src="/src/service/loader-static-files.js"></script>
// Register a loader for the static files // So, the module will search missing translation tables under the specified urls. // Those urls are [prefix][langKey][suffix]. $translateProvider.useStaticFilesLoader({ prefix: '/l10n/', suffix: '.json' });
حال ببینیم که این فرآیند در loader-static-files چگونه پیاده سازی شده است. در این فایل یک متد load نوشته شده است که فایلهای static را طبق یک الگوی مشتمل بر prefix و suffix از سرور میخواند. لزومی ندارد که شما فایلها را حتما به صورت JSON و با این پسوند ذخیره کنید. اما چیزی که قطعی است این است که فایلها حتما باید به صورت key value ذخیره شده باشند.
تکه کد زیر اطلاعات فایل loader-static-files را نمایش میدهد.
angular.module('pascalprecht.translate') .factory('$translateStaticFilesLoader', $translateStaticFilesLoader); function $translateStaticFilesLoader($q, $http) { 'use strict'; return function (options) { if (!options || (!angular.isArray(options.files) && (!angular.isString(options.prefix) || !angular.isString(options.suffix)))) { throw new Error('Couldn\'t load static files, no files and prefix or suffix specified!'); } if (!options.files) { options.files = [{ prefix: options.prefix, suffix: options.suffix }]; } var load = function (file) { if (!file || (!angular.isString(file.prefix) || !angular.isString(file.suffix))) { throw new Error('Couldn\'t load static file, no prefix or suffix specified!'); } var deferred = $q.defer(); $http(angular.extend({ url: [ file.prefix, options.key, file.suffix ].join(''), method: 'GET', params: '' }, options.$http)).success(function (data) { deferred.resolve(data); }).error(function () { deferred.reject(options.key); }); return deferred.promise; }; var deferred = $q.defer(), promises = [], length = options.files.length; for (var i = 0; i < length; i++) { promises.push(load({ prefix: options.files[i].prefix, key: options.key, suffix: options.files[i].suffix })); } $q.all(promises).then(function (data) { var length = data.length, mergedData = {}; for (var i = 0; i < length; i++) { for (var key in data[i]) { mergedData[key] = data[i][key]; } } deferred.resolve(mergedData); }, function (data) { deferred.reject(data); }); return deferred.promise; }; } $translateStaticFilesLoader.displayName = '$translateStaticFilesLoader';
همانطور که ملاحظه میکنید، کد فوق یک سرویس با نام $translateStaticFilesLoader را تعریف نموده است. در صورتیکه ما در کنترلر فایل ex7، اصلا نامی از آن نبردیم و تنها از $translateProvider.useStaticFilesLoader استفاده نمودیم! جواب در نحوهی نگارش کد angular-translate نهفته است. در خط 866 فایل angular-translate تکه کد زیر مربوط به تعریف translateStaticFileLoader میباشد. همانطور که ملاحظه میکنید سرویس translateStaticFilesLoader درون فضای نام سرویس translateTable قرار گرفته است. بنابراین ما تنها با تعریف سرویس translateStaticFilesLoader، در حقیقت آن را override نمودهایم. در کد نمونهای که در بخشهای قبلی قرار دادهام یک فایل translate.js نیز قرار دارد که در فولدر src/services قرار گرفته است. این فایل نیز برخی از امکانات و سرویسهای built-in درون angular-translate را سفارشی نموده است.
/** * @ngdoc function * @name pascalprecht.translate.$translateProvider#useStaticFilesLoader * @methodOf pascalprecht.translate.$translateProvider * * @description * Tells angular-translate to use `$translateStaticFilesLoader` extension service as loader. * * @param {Object=} options Optional configuration object */ this.useStaticFilesLoader = function (options) { return this.useLoader('$translateStaticFilesLoader', options); };
در این 4 مجموعه سعی کردم تمامی آنچه را که برای ایجاد قابلیت چند زبانه و localization نیاز است و حیاتی بود، تشریح کنم. بنابراین تا کنون دانش خوبی دربارهی این کتابخانه کسب نمودهاید. باقی تمرینها را میتوانید بر حسب نیاز با استفاده از مستندات موجود در angular-translate مطالعه و استفاده نمایید.
پیشنیازها
- مطالعهی سری کار با Angular CLI خصوصا قسمت نصب و قسمت ساخت برنامههای آن، پیش از مطالعهی این مطلب ضروری است.
- همچنین فرض بر این است که سری ASP.NET Core را نیز یکبار مرور کردهاید و با نحوهی برپایی یک برنامهی MVC آن و ارائهی فایلهای استاتیک توسط یک پروژهی ASP.NET Core آشنایی دارید.
ایجاد یک پروژهی جدید ASP.NET Core در VS 2017
در ابتدا یک پروژهی خالی ASP.NET Core را در VS 2017 ایجاد خواهیم کرد. برای این منظور:
- ابتدا از طریق منوی File -> New -> Project (Ctrl+Shift+N) گزینهی ایجاد یک ASP.NET Core Web application را انتخاب کنید.
- در صفحهی بعدی آن هم گزینهی «empty template» را انتخاب نمائید.
تنظیمات یک برنامهی ASP.NET Core خالی برای اجرای یک برنامهی Angular CLI
برای اجرای یک برنامهی مبتنی بر Angular CLI، نیاز است بر روی فایل csproj برنامهی ASP.NET Core کلیک راست کرده و گزینهی Edit آنرا انتخاب کنید.
سپس محتوای این فایل را به نحو ذیل تکمیل نمائید:
الف) درخواست عدم کامپایل فایلهای TypeScript
<PropertyGroup> <TargetFramework>netcoreapp1.1</TargetFramework> <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked> </PropertyGroup>
ب) مشخص کردن پوشههایی که باید الحاق و یا حذف شوند
<ItemGroup> <Folder Include="Controllers\" /> <Folder Include="wwwroot\" /> </ItemGroup> <ItemGroup> <Compile Remove="node_modules\**" /> <Content Remove="node_modules\**" /> <EmbeddedResource Remove="node_modules\**" /> <None Remove="node_modules\**" /> </ItemGroup> <ItemGroup> <Compile Remove="src\**" /> <Content Remove="src\**" /> <EmbeddedResource Remove="src\**" /> </ItemGroup>
سپس دو پوشهی node_modules و src واقع در ریشهی پروژه را نیز به طور کامل از سیستم ساخت و توزیع VS 2017 حذف کردهایم. پوشهی node_modules وابستگیهای Angular را به همراه دارد و src همان پوشهی برنامهی Angular ما خواهد بود.
ج) افزودن وابستگیهای سمت سرور مورد نیاز
<ItemGroup> <PackageReference Include="Microsoft.AspNetCore" Version="1.1.1" /> <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" /> <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.1" /> </ItemGroup> <ItemGroup> <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="1.0.0" /> </ItemGroup> <ItemGroup> <!-- extends watching group to include *.js files --> <Watch Include="**\*.js" Exclude="node_modules\**\*;**\*.js.map;obj\**\*;bin\**\*" /> </ItemGroup>
در اینجا Watcher.Tools هم به همراه تنظیمات آن اضافه شدهاند که در ادامهی بحث به آن اشاره خواهد شد.
افزودن یک کنترلر Web API جدید
با توجه به اینکه دیگر در اینجا قرار نیست با فایلهای cshtml و razor کار کنیم، کنترلرهای ما نیز از نوع Web API خواهند بود. البته در ASP.NET Core، کنترلرهای معمولی آن، توانایی ارائهی Web API و همچنین فایلهای Razor را دارند و از این لحاظ تفاوتی بین این دو نیست و یکپارچگی کاملی صورت گرفتهاست.
using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; namespace ASPNETCoreIntegrationWithAngularCLI.Controllers { [Route("api/[controller]")] public class ValuesController : Controller { // GET: api/values [HttpGet] [ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)] public IEnumerable<string> Get() { return new string[] { "Hello", "DNT" }; } } }
تنظیمات فایل آغازین یک برنامهی ASP.NET Core جهت ارائهی برنامههای Angular
در ادامه به فایل Startup.cs برنامهی خالی جاری، مراجعه کرده و آنرا به نحو ذیل تغییر دهید:
using System; using System.IO; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace ASPNETCoreIntegrationWithAngularCLI { public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvc(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.Use(async (context, next) => { await next(); if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value) && !context.Request.Path.Value.StartsWith("/api/", StringComparison.OrdinalIgnoreCase)) { context.Request.Path = "/index.html"; await next(); } }); app.UseMvcWithDefaultRoute(); app.UseDefaultFiles(); app.UseStaticFiles(); } } }
در قسمت app.Use آن، تنظیمات URL Rewriting مورد نیاز جهت کار با مسیریابی برنامههای Angular را مشاهده میکنید. برای نمونه اگر کاربری در ابتدای کار آدرس /products را درخواست کند، این درخواست به سمت سرور ارسال میشود و چون چنین صفحهای در سمت سرور وجود ندارد، خطای 404 بازگشت داده میشود و کار به پردازش برنامهی Angular نخواهد رسید. اینجا است که تنظیم میانافزار فوق، کار مدیریت خروجیهای 404 را بر عهده گرفته و کاربر را به فایل index.html برنامهی تک صفحهای وب، هدایت میکند. به علاوه در اینجا اگر درخواست وارد شده، دارای پسوند باشد (یک فایل باشد) و یا با api/ شروع شود (اشاره کنندهی به کنترلرهای Web API برنامه)، از این پردازش و هدایت به صفحهی index.html معاف خواهد شد.
ایجاد ساختار اولیهی برنامهی Angular CLI در داخل پروژهی جاری
اکنون از طریق خط فرمان به پوشهی ریشهی برنامهی ASP.NET Core، جائیکه فایل Startup.cs قرار دارد، وارد شده و دستور ذیل را اجرا کنید:
>ng new ClientApp --routing --skip-install --skip-git --skip-commit
پس از تولید ساختار برنامهی Angular CLI، به پوشهی آن وارد شده و تمام فایلهای آن را Cut کنید. سپس به پوشهی ریشهی برنامهی ASP.NET Core جاری، وارد شده و این فایلها را در آنجا paste نمائید. به این ترتیب به حداکثر سازگاری ساختار پروژههای Angular CLI و VS 2017 خواهیم رسید. زیرا اکثر فایلهای تنظیمات آنرا میشناسد و قابلیت پردازش آنها را دارد.
پس از این cut/paste، پوشهی خالی ClientApp را نیز حذف کنید.
تنظیم محل خروجی نهایی Angular CLI به پوشهی wwwroot
برای اینکه سیستم Build پروژهی Angular CLI جاری، خروجی خود را در پوشهی wwwroot قرار دهد، تنها کافی است فایل .angular-cli.json را گشوده و outDir آنرا به wwwroot تنظیم کنیم:
"apps": [ { "root": "src", "outDir": "wwwroot",
فراخوانی کنترلر Web API برنامه در برنامهی Angular CLI
در ادامه صرفا جهت آزمایش برنامه، فایل src\app\app.component.ts را گشوده و به نحو ذیل تکمیل کنید:
import { Component, OnInit } from '@angular/core'; import { Http } from '@angular/http'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { constructor(private _httpService: Http) { } apiValues: string[] = []; ngOnInit() { this._httpService.get('/api/values').subscribe(values => { this.apiValues = values.json() as string[]; }); } }
سپس این آرایه را در فایل قالب این کامپوننت (src\app\app.component.html) استفاده خواهیم کرد:
<h1>Application says:</h1> <ul *ngFor="let value of apiValues"> <li>{{value}}</li> </ul> <router-outlet></router-outlet>
نصب وابستگیهای برنامهی Angular CLI
در ابتدای ایجاد پوشهی ClientApp، از پرچم skip-install استفاده شد، تا صرفا ساختار پروژه، جهت cut/paste آن با سرعت هر چه تمامتر، ایجاد شود. اکنون برای نصب وابستگیهای آن یا میتوان در solution explorer به گره dependencies مراجعه کرده و npm را انتخاب کرد. در ادامه با کلیک راست بر روی آن، گزینهی restore packages ظاهر میشود. و یا میتوان به روش متداول این نوع پروژهها، از طریق خط فرمان به پوشهی ریشهی پروژه وارد شد و دستور npm install را صادر کرد. بهتر است اینکار را از طریق خط فرمان انجام دهید تا مطمئن شوید که از آخرین نگارشهای این ابزار که بر روی سیستم نصب شدهاست، استفاده میکنید.
روش اول اجرای برنامههای مبتنی بر ASP.NET Core و Angular CLI
تا اینجا اگر برنامه را از طریق VS 2017 اجرا کنید، خروجی را مشاهده نخواهید کرد. چون هنوز فایل index.html آن تولید نشدهاست.
بنابراین روش اول اجرای این نوع برنامهها، شامل مراحل ذیل است:
الف) ساخت پروژهی Angular CLI در حالت watch
> ng build --watch
ب) اجرای برنامه از طریق ویژوال استودیو
اکنون که کار ایجاد محتوای پوشهی wwwroot برنامه انجام شدهاست، میتوان برنامه را از طریق VS 2017 به روش متداولی اجرا کرد:
یک نکته: میتوان قسمت الف را تبدیل به یک Post Build Event هم کرد. برای این منظور باید فایل csproj را به نحو ذیل تکمیل کرد:
<Target Name="AngularBuild" AfterTargets="Build"> <Exec Command="ng build" /> </Target>
تنها مشکل روش Post Build Event، کند بودن آن است. زمانیکه از روش ng build --watch به صورت مستقل استفاده میشود، برای بار اول اجرا، اندکی زمان خواهد برد؛ اما اعمال تغییرات بعدی به آن بسیار سریع هستند. چون صرفا نیاز دارد این تغییرات اندک و تدریجی را کامپایل کند و نه کامپایل کل پروژه را از ابتدا.
روش دوم اجرای برنامههای مبتنی بر ASP.NET Core و Angular CLI
روش دومی که در اینجا بررسی خواهد شد، مستقل است از قسمت «ب» روش اول که توضیح داده شد. برنامههای NET Core. نیز به همراه CLI خاص خودشان هستند و نیازی نیست تا حتما از VS 2017 برای اجرای آنها استفاده کرد. به همین جهت وابستگی Microsoft.DotNet.Watcher.Tools را نیز در ابتدای کار به وابستگیهای برنامه اضافه کردیم.
الف) در ادامه، VS 2017 را به طور کامل ببندید؛ چون نیازی به آن نیست. سپس دستور ذیل را در خط فرمان، در ریشهی پروژه، صادر کنید:
> dotnet watch run
>dotnet watch run [90mwatch : [39mStarted Hosting environment: Production Now listening on: http://localhost:5000 Application started. Press Ctrl+C to shut down.
ب) در اینجا چون برنامه بر روی پورت 5000 ارائه شدهاست، بهتر است دستور ng serve -o را صادر کرد تا بتوان به نحو سادهتری از سرور وب ASP.NET Core استفاده نمود. در این حالت برنامهی Angular CLI بر روی پورت 4200 ارائه شده و بلافاصله در مرورگر نیز نمایش داده میشود.
مشکل! سرور وب ما بر روی پورت 5000 است و سرور آزمایشی Angular CLI بر روی پورت 4200. اکنون برنامهی Angular ما، یک چنین درخواستهایی را به سمت سرور، جهت دریافت اطلاعات ارسال میکند: localhost:4200/api
برای رفع این مشکل میتوان فایلی را به نام proxy.config.json با محتویات ذیل ایجاد کرد:
{ "/api": { "target": "http://localhost:5000", "secure": false } }
>ng serve --proxy-config proxy.config.json -o
مزیت این روش، به روز رسانی خودکار مرورگر با انجام هر تغییری در کدهای قسمت Angular برنامه است.
نکته 1: بدیهی است میتوان قسمت «ب» روش دوم را با قسمت «الف» روش اول نیز جایگزین کرد (ساخت پروژهی Angular CLI در حالت watch). اینبار گشودن مرورگر بر روی پورت 5000 (و یا آدرس http://localhost:5000) را باید به صورت دستی انجام دهید. همچنین هربار تغییر در کدهای Angular، سبب refresh خودکار مرورگر نیز نمیشود که آنرا نیز باید خودتان به صورت دستی انجام دهید (کلیک بر روی دکمهی refresh پس از هر بار پایان کار ng build).
نکته 2: میتوان قسمت «الف» روش دوم را حذف کرد (حذف dotnet run در حالت watch). یعنی میخواهیم هنوز هم ویژوال استودیو کار آغاز IIS Express را انجام دهد. به علاوه میخواهیم برنامه را توسط ng serve مشاهده کنیم (با همان پارامترهای قسمت «ب» روش دوم). در این حالت تنها موردی را که باید تغییر دهید، پورتی است که برای IIS Express تنظیم شدهاست. عدد این پورت را میتوان در فایل Properties\launchSettings.json مشاهده کرد و سپس به تنظیمات فایل proxy.config.json اعمال نمود.
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید: ASPNETCoreIntegrationWithAngularCLI.zip
به همراه این کدها تعدادی فایل bat نیز وجود دارند که جهت ساده سازی عملیات یاد شدهی در این مطلب، میتوان از آنها استفاده کرد:
- فایل restore.bat کار بازیابی و نصب وابستگیهای پروژهی دات نتی و همچنین Angular CLI را انجام میدهد.
- دو فایل ng-build-dev.bat و ng-build-prod.bat بیانگر قسمت «الف» روش اول هستند. فایل dev مخصوص حالت توسعه است و فایل prod مخصوص ارائهی نهایی.
- دو فایل dotnet_run.bat و ng-serve-proxy.bat خلاصه کنندهی قسمتهای «الف» و «ب» روش دوم هستند.
کلیات پروژه
پیاده سازی
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First(); jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
var angularExample = angular.module('angularexample', ["restangular"]) angularExample.config(["RestangularProvider", function (RestangularProvider) { //RestangularProvider.setRestangularFields({ // id: "id" //}); RestangularProvider.setBaseUrl('/api'); }]); angularExample.controller("MainCtrl", ["Restangular", "$scope", function (Restangular, $scope) { var resource = Restangular.all('books'); resource.getList().then(function (response) { $scope.books = response; }); $scope.add = function () { resource.post($scope.newBook).then(function (newResource) { $scope.books.push(newResource); }) } }]);
<!DOCTYPE html> <html ng-app="angularexample" xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Rest Angular Sample</title> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js"></script> <script src="http://cdn.jsdelivr.net/underscorejs/1.5.1/underscore-min.js"></script> <script src="/Scripts/restangular.min.js"></script> <script src="/app/app.js"></script> </head> <body> <div ng-controller="MainCtrl"> <div ng-repeat="item in books"> name is: {{item.name}}<br /> change name: <input type="text" ng-model="item.name" /><button type="submit" ng-click="item.put();">update</button> </div> <div> add new: <br /> <input type="text" ng-model="newBook.name" /><button type="submit" ng-click="add()">add</button> </div> </div> </body>
var resource = Restangular.all('books'); resource.getList().then(function (response) { $scope.books = response; });
$scope.add = function () { resource.post($scope.newBook).then(function (newResource) { $scope.books.push(newResource); }) }
<div ng-repeat="item in books"> name is: {{item.name}}<br /> change name: <input type="text" ng-model="item.name" /><button type="submit" ng-click="item.put();">update</button> </div>
سورس پروژه: RestangularSample.rar
ایزوله کردن ngmodel در آنگولار 2
پروژه Smart Table
Smart table is an Angularjs module to easily display data in a table