تیم Angular در حال تهیهی پروژهای است به نام Angular Language Service که به عنوان افزونهای برای ادیتورها جهت درک بهتر قالبهای کامپوننتها بکار میرود.
اشتراکها
تیم Angular در حال تهیهی پروژهای است به نام Angular Language Service که به عنوان افزونهای برای ادیتورها جهت درک بهتر قالبهای کامپوننتها بکار میرود.
import { Location } from "@angular/common";
dotnet new angular
• Boolean • Null • Undefined • Number • String
• Arrays • Objects • Functions
import {ChangeDetectionStrategy, Component} from '@angular/core'; @Component({ // ... changeDetection: ChangeDetectionStrategy.OnPush }) export class OnPushComponent { // ... }
static mutable() { var before = {foo: "bar"}; var current = before; current.foo = "hello"; console.log(before === current); // => true }
static immutable() { var before = {foo: "bar"}; var current = before; current = {foo: "hello"}; console.log(before === current); // => false }
npm install immutable --save
import {Map, List} from 'immutable'; var foobar = {foo: "bar"}; var immutableFoobar = Map(foobar); console.log(immutableFooter.get("foo")); // => bar var helloWorld = ["Hello", "World!"]; var immutableHelloWorld = List(helloWorld); console.log(immutableHelloWorld.first()); // => Hello console.log(immutableHelloWorld.last()); // => World! helloWorld.push("Hello Mars!"); console.log(immutableHelloWorld.last()); // => Hello Mars!
const user = { name: 'Max', age: 30 } user.age = 31
const user = { name: 'Max', age: 30 } const modifiedUser = { ...user, age: 31 }
export class AppComponent { foods = ['Bacon', 'Lettuce', 'Tomatoes']; addFood(food) { this.foods.push(food); } }
addFood(food) { this.foods = [...this.foods, food]; }
import { Component, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; @Component({ selector: 'app-child', templateUrl: './child.component.html', changeDetection: ChangeDetectionStrategy.OnPush }) export class ChildComponent { @Input() data: string[]; constructor(private cd: ChangeDetectorRef) {} refresh() { this.cd.detectChanges(); } }
import { Component } from '@angular/core'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; @Component({ ... }) export class AppComponent { foods = new BehaviorSubject(['Bacon', 'Letuce', 'Tomatoes']); addFood(food) { this.foods.next(food); } }
import { Component, Input, ChangeDetectionStrategy, ChangeDetectorRef, OnInit } from '@angular/core'; import { Observable } from 'rxjs/Observable'; @Component({ selector: 'app-child', templateUrl: './child.component.html', changeDetection: ChangeDetectionStrategy.OnPush }) export class ChildComponent implements OnInit { @Input() data: Observable<any>; foods: string[] = []; constructor(private cd: ChangeDetectorRef) {} ngOnInit() { this.data.subscribe(food => { this.foods = [...this.foods, ...food]; }); }
ngOnInit() { this.data.subscribe(food => { this.foods = [...this.foods, ...food]; this.cd.markForCheck(); // marks path }); }
namespace AngularTemplateDrivenFormsLab.Models { public class Product { public int ProductId { set; get; } public string ProductName { set; get; } public decimal Price { set; get; } public bool IsAvailable { set; get; } } }
using System.Collections.Generic; namespace AngularTemplateDrivenFormsLab.Models { public static class ProductDataSource { private static readonly IList<Product> _cachedItems; static ProductDataSource() { _cachedItems = createProductsDataSource(); } public static IList<Product> LatestProducts { get { return _cachedItems; } } private static IList<Product> createProductsDataSource() { var list = new List<Product>(); for (var i = 0; i < 1500; i++) { list.Add(new Product { ProductId = i + 1, ProductName = "نام " + (i + 1), IsAvailable = (i % 2 == 0), Price = 1000 + i }); } return list; } } }
http://localhost:5000/api/Product/GetPagedProducts?sortBy=productId&isAscending=true&page=2&pageSize=7
public interface IPagedQueryModel { string SortBy { get; set; } bool IsAscending { get; set; } int Page { get; set; } int PageSize { get; set; } }
public class ProductQueryViewModel : IPagedQueryModel { // ... other properties ... public string SortBy { get; set; } public bool IsAscending { get; set; } public int Page { get; set; } public int PageSize { get; set; } }
public static class IQueryableExtensions { public static IQueryable<T> ApplyPaging<T>( this IQueryable<T> query, IPagedQueryModel model) { if (model.Page <= 0) { model.Page = 1; } if (model.PageSize <= 0) { model.PageSize = 10; } return query.Skip((model.Page - 1) * model.PageSize).Take(model.PageSize); } }
http://localhost:5000/api/Product/GetPagedProducts?sortBy=productId&isAscending=true&page=2&pageSize=7
if(model.SortBy == "f1") { query = !model.IsAscending ? query.OrderByDescending(x => x.F1) : query.OrderBy(x => x.F1); }
namespace AngularTemplateDrivenFormsLab.Utils { public static class IQueryableExtensions { public static IQueryable<T> ApplyOrdering<T>( this IQueryable<T> query, IPagedQueryModel model, IDictionary<string, Expression<Func<T, object>>> columnsMap) { if (string.IsNullOrWhiteSpace(model.SortBy) || !columnsMap.ContainsKey(model.SortBy)) { return query; } if (model.IsAscending) { return query.OrderBy(columnsMap[model.SortBy]); } else { return query.OrderByDescending(columnsMap[model.SortBy]); } } } }
var columnsMap = new Dictionary<string, Expression<Func<Product, object>>>() { ["productId"] = p => p.ProductId, ["productName"] = p => p.ProductName, ["isAvailable"] = p => p.IsAvailable, ["price"] = p => p.Price }; query = query.ApplyOrdering(queryModel, columnsMap);
using System.Collections.Generic; namespace AngularTemplateDrivenFormsLab.Models { public class PagedQueryResult<T> { public int TotalItems { get; set; } public IEnumerable<T> Items { get; set; } } }
[Route("api/[controller]")] public class ProductController : Controller { [HttpGet("[action]")] public PagedQueryResult<Product> GetPagedProducts(ProductQueryViewModel queryModel) { var pagedResult = new PagedQueryResult<Product>(); var query = ProductDataSource.LatestProducts .AsQueryable(); //TODO: Apply Filtering ... .where(p => p....) ... var columnsMap = new Dictionary<string, Expression<Func<Product, object>>>() { ["productId"] = p => p.ProductId, ["productName"] = p => p.ProductName, ["isAvailable"] = p => p.IsAvailable, ["price"] = p => p.Price }; query = query.ApplyOrdering(queryModel, columnsMap); pagedResult.TotalItems = query.Count(); query = query.ApplyPaging(queryModel); pagedResult.Items = query.ToList(); return pagedResult; } }
public PagedQueryResult<Product> GetPagedProducts(ProductQueryViewModel queryModel)
var query = ProductDataSource.LatestProducts .AsQueryable(); //TODO: Apply Filtering ... .where(p => p....) ...
var columnsMap = new Dictionary<string, Expression<Func<Product, object>>>() { ["productId"] = p => p.ProductId, ["productName"] = p => p.ProductName, ["isAvailable"] = p => p.IsAvailable, ["price"] = p => p.Price }; query = query.ApplyOrdering(queryModel, columnsMap);
var pagedResult = new PagedQueryResult<Product>(); pagedResult.TotalItems = query.Count(); query = query.ApplyPaging(queryModel); pagedResult.Items = query.ToList(); return pagedResult;
public class Product { public int Id { set; get; } public DateTime AddDate { set; get; } public string Name { set; get; } public decimal Price { set; get; } }
<!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="~/Content/themes/base/jquery.ui.all.css" rel="stylesheet" /> <link href="~/Content/jquery.jqGrid/ui.jqgrid.css" rel="stylesheet" /> <link href="~/Content/PersianDatePicker.css" rel="stylesheet" /> <link href="~/Content/Site.css" rel="stylesheet" type="text/css" /> </head> <body> <div> @RenderBody() </div> <script src="~/Scripts/jquery-1.7.2.min.js"></script> <script src="~/Scripts/jquery-ui-1.8.11.min.js"></script> <script src="~/Scripts/i18n/grid.locale-fa.js"></script> <script src="~/Scripts/jquery.jqGrid.min.js"></script> <script src="~/Scripts/PersianDatePicker.js"></script> <script src="~/Scripts/jquery.price_format.2.0.js"></script> @RenderSection("Scripts", required: false) </body> </html>
colModel: [ { name: 'Name', index: 'Name', align: 'right', width: 100, editable: true, edittype: 'text', editoptions: { maxlength: 40, dataInit: function (elem) { // http://jqueryui.com/autocomplete/ $(elem).autocomplete({ source: '@Url.Action("GetProductNames","Home")', minLength: 2, select: function (event, ui) { $(elem).val(ui.item.value); $(elem).trigger('change'); } }); } }, editrules: { required: true } } ],
public ActionResult GetProductNames(string term) { var list = ProductDataSource.LatestProducts .Where(x => x.Name.StartsWith(term)) .Select(x => x.Name) .Take(10) .ToArray(); return Json(list, JsonRequestBehavior.AllowGet); }
colModel: [ { name: 'AddDate', index: 'AddDate', align: 'center', width: 100, editable: true, edittype: 'text', editoptions: { maxlength: 10, // https://www.dntips.ir/post/1382 onclick: "PersianDatePicker.Show(this,'@today');" }, editrules: { required: true } } ],
@{ ViewBag.Title = "Index"; var today = DateTime.Now.ToPersianDate(); }
colModel: [ { name: 'Price', index: 'Price', align: 'center', width: 100, formatter: 'currency', formatoptions: { decimalSeparator: '.', thousandsSeparator: ',', decimalPlaces: 2, prefix: '$' }, editable: true, edittype: 'text', editoptions: { dir: 'ltr', dataInit: function (elem) { // http://jquerypriceformat.com/ $(elem).priceFormat({ prefix: '', thousandsSeparator: ',', clearPrefix: true, centsSeparator: '', centsLimit: 0 }); } }, editrules: { required: true, minValue: 0 } } ],
using System; using System.Globalization; using System.Threading; using System.Web.Mvc; namespace jqGrid05.CustomModelBinders { /// <summary> /// How to register it in the Application_Start method of Global.asax.cs /// ModelBinders.Binders.Add(typeof(decimal), new DecimalBinder()); /// </summary> public class DecimalBinder : DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { if (bindingContext.ModelType == typeof(decimal) || bindingContext.ModelType == typeof(decimal?)) { return bindDecimal(bindingContext); } return base.BindModel(controllerContext, bindingContext); } private static object bindDecimal(ModelBindingContext bindingContext) { var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); if (valueProviderResult == null) return null; bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); decimal value; var valueAsString = valueProviderResult.AttemptedValue == null ? null : valueProviderResult.AttemptedValue.Trim(); if (string.IsNullOrEmpty(valueAsString)) return null; if (!decimal.TryParse(valueAsString, NumberStyles.Any, Thread.CurrentThread.CurrentCulture, out value)) { const string error ="عدد وارد شده معتبر نیست"; var ex = new InvalidOperationException(error, new Exception(error, new FormatException(error))); bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex); return null; } return value; } } }
using System; using System.Web.Mvc; using System.Web.Routing; using jqGrid05.CustomModelBinders; namespace jqGrid05 { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); ModelBinders.Binders.Add(typeof(DateTime), new PersianDateModelBinder()); ModelBinders.Binders.Add(typeof(decimal), new DecimalBinder()); } } }
app.config([ '$stateProvider', '$urlRouterProvider', '$locationProvider', '$controllerProvider', '$compileProvider', '$filterProvider', '$provide', function ($stateProvider, $urlRouterProvider, $locationProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) { //برای رجیستر کردن غیر همروند اجزای انگیولاری در آینده app.lazy = { controller: $controllerProvider.register, directive: $compileProvider.directive, filter: $filterProvider.register, factory: $provide.factory, service: $provide.service }; . . . ])
angular.module('app').lazy.controller('myController', ['$scope', function($scope){ ... }]);
<script type="text/javascript"> // --- Scriptjs --- !function (a, b, c) { function t(a, c) { var e = b.createElement("script"), f = j; e.onload = e.onerror = e[o] = function () { e[m] && !/^c|loade/.test(e[m]) || f || (e.onload = e[o] = null, f = 1, c()) }, e.async = 1, e.src = a, d.insertBefore(e, d.firstChild) } function q(a, b) { p(a, function (a) { return !b(a) }) } var d = b.getElementsByTagName("head")[0], e = {}, f = {}, g = {}, h = {}, i = "string", j = !1, k = "push", l = "DOMContentLoaded", m = "readyState", n = "addEventListener", o = "onreadystatechange", p = function (a, b) { for (var c = 0, d = a.length; c < d; ++c) if (!b(a[c])) return j; return 1 }; !b[m] && b[n] && (b[n](l, function r() { b.removeEventListener(l, r, j), b[m] = "complete" }, j), b[m] = "loading"); var s = function (a, b, d) { function o() { if (!--m) { e[l] = 1, j && j(); for (var a in g) p(a.split("|"), n) && !q(g[a], n) && (g[a] = []) } } function n(a) { return a.call ? a() : e[a] } a = a[k] ? a : [a]; var i = b && b.call, j = i ? b : d, l = i ? a.join("") : b, m = a.length; c(function () { q(a, function (a) { h[a] ? (l && (f[l] = 1), o()) : (h[a] = 1, l && (f[l] = 1), t(s.path ? s.path + a + ".js" : a, o)) }) }, 0); return s }; s.get = t, s.ready = function (a, b, c) { a = a[k] ? a : [a]; var d = []; !q(a, function (a) { e[a] || d[k](a) }) && p(a, function (a) { return e[a] }) ? b() : !function (a) { g[a] = g[a] || [], g[a][k](b), c && c(d) }(a.join("|")); return s }; var u = a.$script; s.noConflict = function () { a.$script = u; return this }, typeof module != "undefined" && module.exports ? module.exports = s : a.$script = s }(this, document, setTimeout) $script(['/Scripts/Lib/jquery/jquery-1.10.2.min.js'], function () { $script(['/Scripts/Lib/angular/angular.js'], function () { $script(['/Scripts/Lib/angular/angular-ui-router.min.js', '/Scripts/Lib/angular/angular-resource.min.js', '/Scripts/Lib/angular/angular-cache.min.js', '/Scripts/Lib/angular/angular-sanitize.min.js', '/Scripts/Lib/angular/angular-animate.min.js', '/Scripts/Lib/angular/angular-cookie.min.js', '/APP/Common/directives.js' ], function () { $script('/app/app.js', function () { angular.bootstrap(document, ['app']); }); }); }) }); </script>
resolve: { fileDeps: ['$q', '$rootScope', function ($q, $rootScope) { var deferred = $q.defer(); var deps = ['/app/HotStories/dataContextService.js', '/app/HotStories/hotStController.js']; $script(deps, function () { $rootScope.$apply(function () { deferred.resolve(); }); }); return deferred.promise; }] }
angular.module('app').lazy.service('dataContextService', ['$rootScope', '$resource', '$angularCacheFactory', '$q', function($rootScope, $resource, $cacheFactory, $q){ ... }]);
angular.module('app').lazy.controller('hotStController', ['$scope', 'ipCookie', 'dataContextService', function($scope, ipCookie, dataContextService){ ... }]);