نظرات مطالب
راه اندازی StimulSoft Report در ASP.NET MVC
در سمت سرور کلاس‌هایی به صورت زیر می‌توانید داشته باشید:
public class PlanModel
{
    public int RId { get; set; }
    public string Day { get; set; }
    public string Plan { get; set; }
    public List<RecordModel> Records { get; set; }
}

public class RecordModel
{
    public int RId { get; set; }
    public string Help { get; set; }
}
که لیستی از PlanModel پس از فراهم کردن اطلاعاتش،  به گزارش ارسال می‌کنید.
در فایل mrt گزارش خود نیز در قسمت Business Objects دو Business Object تولید می‌کنید، که مدل دوم (از نوع RecordModel) به عنوان فرزند مدل اول (از نوع PlanModel) است.

برای نمایش اطلاعات این دو مدل هم، به دو Data band احتیاج دارید.

 نکته‌ای که در اینجا مهم است باید پراپرتی Master Component، بند دوم برابر بند اول مقداردهی شود.
نمونه فایل: MultiBusinessObject.mrt 
مطالب دوره‌ها
تغییر ترتیب آیتم‌های یک لیست به کمک افزونه jquery.sortable در ASP.NET MVC
در این مطلب قصد داریم ترتیب عناصر نمایش داده شده توسط یک لیست را به کمک افزونه بسیار سبک وزن jquery.sortable تغییر داده و نتایج را در سمت سرور مدیریت کنیم. این افزونه بر اساس امکانات کشیدن و رها ساختن HTML5 کار می‌کند و با مرورگرهای IE8 به بعد سازگار است.

مدل‌های برنامه

using System.Collections.Generic;

namespace jQueryMvcSample05.Models
{
    public class Survey
    {
        public int Id { set; get; }
        public string Title { set; get; }

        public virtual ICollection<SurveyItem> SurveyItems { set; get; }
    }
}

namespace jQueryMvcSample05.Models
{
    public class SurveyItem
    {
        public int Id { set; get; }
        public string Title { set; get; }
        public int Order { set; get; }

        //[ForeignKey("SurveyId")]
        public virtual Survey Survey { set; get; }
        public int SurveyId { set; get; }
    }
}
به کمک این ساختار قصد داریم اطلاعات یک سیستم نظر سنجی را نمایش دهیم.
تعدادی نظر سنجی به همراه گزینه‌های آن‌ها تعریف خواهند شد (یک رابطه one-to-many است). سپس توسط افزونه sortable می‌خواهیم ترتیب قرارگیری گزینه‌های آن‌را مشخص کنیم یا تغییر دهیم.


منبع داده فرضی برنامه


using System.Collections.Generic;
using jQueryMvcSample05.Models;

namespace jQueryMvcSample05.DataSource
{
    /// <summary>
    /// یک منبع داده فرضی جهت دموی ساده‌تر برنامه
    /// </summary>
    public static class SurveysDataSource
    {
        private static IList<Survey> _surveysCache;
        static SurveysDataSource()
        {
            _surveysCache = createSurveys();
        }

        public static IList<Survey> SystemSurveys
        {
            get { return _surveysCache; }
        }

        private static IList<Survey> createSurveys()
        {
            var results = new List<Survey>();
            for (int i = 1; i < 6; i++)
            {
                results.Add(new Survey
                {
                    Id = i,
                    Title = "نظر سنجی " + i,
                    SurveyItems = new List<SurveyItem>
                    {
                       new SurveyItem{ Id = 1, SurveyId = i, Title = "گزینه 1", Order = 1 },
                       new SurveyItem{ Id = 2, SurveyId = i, Title = "گزینه 2", Order = 2 },
                       new SurveyItem{ Id = 3, SurveyId = i, Title = "گزینه 3", Order = 3 },
                       new SurveyItem{ Id = 4, SurveyId = i, Title = "گزینه 4", Order = 4 }
                    }
                });
            }
            return results;
        }
    }
}
در اینجا نیز از یک منبع داده فرضی تشکیل شده در حافظه جهت سهولت دموی برنامه استفاده خواهد شد.


کدهای کنترلر برنامه

using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.UI;
using jQueryMvcSample05.DataSource;
using jQueryMvcSample05.Security;

namespace jQueryMvcSample05.Controllers
{
    public class HomeController : Controller
    {
        [HttpGet]
        public ActionResult Index()
        {
            var surveysList = SurveysDataSource.SystemSurveys;
            return View(surveysList);
        }

        [HttpPost]
        [AjaxOnly]
        [OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
        public ActionResult SortItems(int? surveyId, string[] items)
        {
            if (items == null || items.Length == 0 || surveyId == null)
                return Content("nok");

            updateSurvey(surveyId, items);

            return Content("ok");
        }

        /// <summary>
        /// این متد جهت آشنایی با پروسه به روز رسانی ترتیب گزینه‌ها در اینجا قرار گرفته است
        /// بدیهی است محل قرارگیری آن باید در لایه سرویس برنامه اصلی باشد
        /// </summary>
        private static void updateSurvey(int? surveyId, string[] items)
        {
            var itemIds = new List<int>();
            foreach (var item in items)
            {
                itemIds.Add(int.Parse(item.Replace("item-row-", string.Empty)));
            }

            var survey = SurveysDataSource.SystemSurveys.FirstOrDefault(x => x.Id == surveyId.Value);
            if (survey == null)
                return;

            int order = 0;
            foreach (var itemId in itemIds)
            {
                order++;
                var surveyItem = survey.SurveyItems.FirstOrDefault(x => x.Id == itemId);
                if (surveyItem == null) continue;
                surveyItem.Order = order;
            }

            //todo: call save changes ....
        }
    }
}

و کدهای View متناظر

@model IList<jQueryMvcSample05.Models.Survey>
@{
    ViewBag.Title = "Index";
    var sortUrl = Url.Action(actionName: "SortItems", controllerName: "Home");
}
<h2>
    نظر سنجی‌ها</h2>
@foreach (var survey in Model)
{
    <fieldset>
        <legend>@survey.Title</legend>
        <div id="sortable-@survey.Id">
            @foreach (var surveyItem in survey.SurveyItems.OrderBy(x => x.Order))
            {            
                <div id="item-row-@surveyItem.Id">
                    <span class="handles">::</span>
                    @surveyItem.Title
                </div>
            }
        </div>
    </fieldset>
}
<div>
    لطفا برای تغییر ترتیب آیتم‌های تعریف شده، از امکان کشیدن و رها کردن تعریف شده بر
    روی آیکون‌های :: در کنار هر آیتم استفاده نمائید.
</div>
@section JavaScript
{
    <script type="text/javascript">
        $(document).ready(function () {
            $('div[id^="sortable"]').sortable({ handle: 'span' }).bind('sortupdate', function (e, ui) {
                var sortableItemId = $(ui.item).parent().attr('id');
                var surveyId = sortableItemId.replace('sortable-', '');
                var items = [];
                $('#' + sortableItemId + ' div').each(function () {
                    items.push($(this).attr('id'));
                });
                //alert(items.join('&'));                
                $.ajax({
                    type: "POST",
                    url: "@sortUrl",
                    data: JSON.stringify({ items: items, surveyId: surveyId }),
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    complete: function (xhr, status) {
                        var data = xhr.responseText;
                        if (xhr.status == 403) {
                            window.location = "/login";
                        } else if (status === 'error' || !data || data == "nok") {
                            alert('خطایی رخ داده است');
                        }
                        else {
                            alert('انجام شد');
                        }
                    }
                });
            });
        });
    </script>
}
توضیحات

در اینجا نیاز بود تا ابتدا کدهای کنترلر و View ارائه شوند، تا بتوان در مورد ارتباطات بین آن‌ها بهتر بحث کرد.
در ابتدای نمایش صفحه Home، رکوردهای نظرسنجی‌ها از منبع داده دریافت شده و به View ارسال می‌شوند. در View برنامه یک حلقه تشکیل گردیده و این موارد رندر خواهند شد.
هر نظر سنجی با یک div بیرونی که با id مساوی sortable شروع می‌شود، آغاز گردیده و گزینه‌های آن نظر سنجی نیز توسط divهایی با id مساوی item-row شروع خواهند گردید. هر کدام از این idها حاوی id رکوردهای متناظر هستند. از این id‌ها در کدهای برنامه جهت یافتن یک نظر سنجی یا یک ردیف مشخص برای به روز رسانی ترتیب آن‌ها استفاده خواهیم کرد.
ادامه کار، به تنظیمات و اعمال افزونه sortable مرتبط می‌شود. توسط تنظیم ذیل به jQuery اعلام خواهیم کرد، هرجایی یک div با id شروع شده با sortable یافتی، افزونه sortable را به آن متصل کن:
 $('div[id^="sortable"]').sortable
در ادامه در ناحیه و  div ایی که عمل کشیدن و رها شدن رخ داده، id این div را بدست آورده و سپس کلیه row-itemهای آن را در آرایه‌ای به نام items قرار می‌دهیم:
 var sortableItemId = $(ui.item).parent().attr('id');
var surveyId = sortableItemId.replace('sortable-', '');
var items = [];
$('#' + sortableItemId + ' div').each(function () {
  items.push($(this).attr('id'));
});
اکنون که به id یک نظر سنجی و همچنین idهای ردیف‌های مرتب شده حاصل دسترسی داریم، آن‌ها را توسط jQuery Ajax به کنترلر برنامه ارسال می‌کنیم:
 data: JSON.stringify({ items: items, surveyId: surveyId })
امضای اکشن متد SortItems نیز دقیقا بر همین مبنا تنظیم شده است:
 public ActionResult SortItems(int? surveyId, string[] items)

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


دریافت کدها و پروژه کامل این قسمت
jQueryMvcSample05.zip
 
مطالب
مقیدسازی (DataBinding) در WPF زمانی که دسترسی به DataContext وجود ندارد

در WPF و Silverlight می‌توان با استفاده از مقید سازی (DataBindingکنترل‌ها را به منبع‌های داده متصل کرد. این منابع به چند شیوه مختلف مانند استفاده مستقیم از خصوصیتSource  قابل دسترسی هستند. یکی از این روش ها، ارث بری از DataContext نزدیک‌ترین والد است.

همانطور که گفته شدDataContext  هر کنترل، توسط تمامی فرزندان آن قابل دسترسی است. اما در بعضی مواقع، زمانیکه کنترل فرزند، بخشی از visual یا logical tree نباشند، دسترسی به DataContext وجود ندارد.

برای مثال زمانی که نیاز است خصوصیت ItemsSource مربوط به یک به لیستی خارج از ItemsSource کنترل DataGrid DataGridTemplateColumn مثلا به لیستی درون ViewModel  مربوط به Window در مثال زیر مقید شود، به صورت معمول باید به این صورت عمل کرد:

ViewModel :

public List<People> ComboBoxDataSource{get; set;}

  : XAML

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        x:Name="this">
    <Grid>
        <DataGrid ItemsSource="{Binding DataCollection}">
            <DataGrid.Columns>
                <DataGridComboBoxColumn ItemsSource="{Binding DataContext.ComboBoxDataSource, ElementName=this}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

با اینکه همه چیز درست به نظر می‌رسد اما در عمل هیچ اتصالی صورت نمی‌گیرد و در پنجره Output ویژوال استادیو خطای زیر مشاهده می‌شود:

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element.
BindingExpression:Path=ComboBoxDataSource; DataItem=null; 
target element is 'DataGridComboBoxColumn' (HashCode=17334644); target property is 'ItemsSource' (type 'IEnumerable')

این خطا مشخص میکند که WPF نمیتواند تشخیص بدهد که کدام FrameWorkElement قرار است از DataContext استفاده کند؛ چرا که همانطور که قبلا عنوان شد DataGridTemplateColumn بخشی از visual  یا  logical treeنیست.

برای مشکل فوق در صورتیکه خصوصیت مورد نظر، یک خصوصیت از فرزندان کنترل باشد، از طریق استایل‌ها می‌توان مشکل را حل کرد. برای مثال به جای ItemSource مربوط به DataGridComboBoxColumn می‌توان خصوصیت ItemSource کنترل ComboBox درون آن را تنظیم کرد.

  <DataGridComboBoxColumn DisplayMemberPath="FirstName">
        <DataGridComboBoxColumn.EditingElementStyle>
              <Style TargetType="ComboBox">
                     <Setter Property="ItemsSource" Value="{Binding DataContext.ComboBoxDataSource , ElementName=this}"/>
               </Style>
         </DataGridComboBoxColumn.EditingElementStyle>
   </DataGridComboBoxColumn>

اما در صورتیکه نیاز باشد یک خصوصیت از خود DataGridComboBoxColumn مانند Visibility  مقید سازی شود، روش بالا کارساز نخواهد بود. برای حل مشکل فوق میتوان از کلاس‌های Freezable استفاده کرد؛ چرا که این کلاسها می‌توانند از DataContext ارث بری کنند حتی زمانیکه بخشی از visual یاlogical tree  نباشند. برای این کار می‌توان کلاس زیر را ایجاد کرد:

 public class DataBindingHelper : Freezable
    {
        protected override Freezable CreateInstanceCore()
        {
            return new DataBindingHelper();
        }
        public object Data
        {
            get { return (object)GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }

        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(object), typeof(DataBindingHelper), new UIPropertyMetadata(null));
    }
و یک نمونه از آن را در Resource‌های DataGrid ساخت:

<DataGrid.Resources>
       <local:DataBindingHelper x:Key="bindingHelper"Data="{Binding}"/>
</DataGrid.Resources>

و هنگام مقید سازی خصوصیت Visibility مربوط به DataGridComboBoxColumn، از نمونه ساخته شده به عنوان  Source استفاده نمود.

<DataGridComboBoxColumn Visibility="{Binding Data.IsVisible,Converter={StaticResource visibilityConverter},Source={StaticResource bindingHelper}}"/>

نظرات نظرسنجی‌ها
کدامیک از قلم‌های فارسی ذیل خواناتر هستند؟
عموما این ناراضی زمانی دیده میشه که از کاربران نظرسنجی بشه. کاربران فقط یک موقع خودجوش اعتراض میکنن که فونت واقعا خیلی مشکل داشته باشه یا سال‌ها با یک فونت کار کرده باشند و در یک مرحله زمانی فونت به یک نمونه بدتر تغییر پیدا کنه.
در بقیه حالات حتی اگ هم ناراضی باشن سخنی نمی‌گویند ولی در یک نظرسنجی که کاربر دو نمونه رو ببینه میشه به نکات مهمتری رسید. فونت یکان یکی از فونت‌های مورد علاقه من هست ولی در وب رضایت چندانی ازش ندارم. هر چند تا مدت‌ها جز معدود فونت‌های مجاز و خوب بود. دلیل اینکه ازش ناراضی هستم این هست که چندان برای وب بهینه نیست و در حالت‌های سایز خیلی بزرگ و کوچک فرم خودش رو از دست میده ولی وزیر و صمیم این مشکل چندان حاد نیست. چون بسیار بهینه‌تر شدند یا مثلا تاهما تا موقعی که 9pt هست بسیار خوب عمل می‌کنه، بزرگتر بشه به یک فاجعه تبدیل میشه. من از صمیم راضی هستم چون واقعا برای خواندن مطالب بلند برای چشم عالی هست. خیلی حالت رسمی داره.
نظرات نظرسنجی‌ها
آخرین باری که یک کتاب فارسی را در زمینه‌ی دات نت خریدید، کی بوده؟

اصولا خوندن کتاب کاغذی را نسبت به PDF   ترجیح می‌دم اگه فارسی هم باشه چه بهتر

به نظر من کتاب‌های فارسی :

اکثرا ترجمه روانی ندارند یا بعضی از لغت‌ها بهتره ترجمه نشه که ترجمه شده (بعضی وقت‌ها فکر می‌کنی گوگل ترجمه کرده یا یک فرد غیر متخصص که تجربه ای در این رشته نداره)

این کتاب‌ها بومی نشده اند (اگه تالیف یک کتاب سخته حداقل می‌تونه لابه لای مطالب اون نکات و یا ابزارهایی که برای خواننده ایرانی مهم است باشه )

نمونه بد اون

مثلا کتاب Visual C# 2010 ترجمه احمد پهلوان انتشارات ناقوس که فصل آخر اون که راجب وب سرویس هست هر جایی که باید مینوشته WCF به اشتباه نوشته WPF و خیلی مشکلات دیگه

و یه نمونه خوب که مشکلات بالا رو نداره

سری آموزشی ASP.NET MVC وحید نصیری که اگه چاپ شده بود حتما می‌خریدمش 

مطالب دوره‌ها
استفاده از StructureMap جهت تزریق وابستگی‌ها در برنامه‌های WPF و الگوی MVVM
در این قسمت قصد داریم همانند کنترلرها در ASP.NET MVC، کار تزریق وابستگی‌ها را در متدهای سازنده ViewModelهای WPF بدون استفاده از الگوی Service locator انجام دهیم؛ برای مثال:
    public class TestViewModel
    {
        private readonly ITestService _testService;
        public TestViewModel(ITestService testService) //تزریق وابستگی در سازنده کلاس
        {
            _testService = testService;
        }
و همچنین کار اتصال یک ViewModel، به View متناظر آن‌را نیز خودکار کنیم. قراردادی را نیز در اینجا بکار خواهیم گرفت:
نام تمام Viewهای برنامه به View ختم می‌شوند و نام ViewModelها به ViewModel. برای مثال TestViewModel و TestView معرف یک ViewModel و View متناظر خواهند بود.


ساختار کلاس‌های لایه سرویس برنامه

namespace DI07.Services
{
    public interface ITestService
    {
        string Test();
    }
}

namespace DI07.Services
{
    public class TestService: ITestService
    {
        public string Test()
        {
            return "برای آزمایش";
        }
    }
}
یک پروژه WPF را آغاز کرده و سپس یک پروژه Class library دیگر را به نام Services با دو کلاس و اینترفیس فوق، به آن اضافه کنید. هدف از این کلاس‌ها صرفا آشنایی با نحوه تزریق وابستگی‌ها در سازنده یک کلاس ViewModel در WPF است.


علامتگذاری ViewModelها

در ادامه یک اینترفیس خالی را به نام IViewModel مشاهده می‌کنید:
namespace DI07.Core
{
    public interface IViewModel // از این اینترفیس خالی برای یافتن و علامتگذاری ویوو مدل‌ها استفاده می‌کنیم
    {
    }
}
از این اینترفیس برای علامتگذاری ViewModelهای برنامه استفاده خواهد شد. این روش، یکی از انواع روش‌هایی است که در مباحث Reflection برای یافتن کلاس‌هایی از نوع مشخص استفاده می‌شود.
برای نمونه کلاس TestViewModel برنامه، با پیاده سازی IViewModel، به نوعی نشانه گذاری نیز شده است:
using DI07.Services;
using DI07.Core;

namespace DI07.ViewModels
{
    public class TestViewModel : IViewModel // علامتگذاری ویوو مدل
    {
        private readonly ITestService _testService;
        public TestViewModel(ITestService testService) //تزریق وابستگی در سازنده کلاس
        {
            _testService = testService;
        }

        public string Data
        {
            get { return _testService.Test(); }
        }
    }
}


تنظیمات آغازین IoC Container مورد استفاده

در کلاس استاندارد App برنامه WPF خود، کار تنظیمات اولیه StructureMap را انجام خواهیم داد:
using System.Windows;
using DI07.Core;
using DI07.Services;
using StructureMap;

namespace DI07
{
    public partial class App
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            ObjectFactory.Configure(cfg =>
            {
                cfg.For<ITestService>().Use<TestService>();

                cfg.Scan(scan =>
                {
                    scan.TheCallingAssembly();
                    // Add all types that implement IView into the container, 
                    // and name each specific type by the short type name.
                    scan.AddAllTypesOf<IViewModel>().NameBy(type => type.Name);
                    scan.WithDefaultConventions();
                });
            });
        }
    }
}
در اینجا عنوان شده است که اگر نیاز به نوع ITestService وجود داشت، کلاس TestService را وهله سازی کن.
همچنین در ادامه از قابلیت اسکن این IoC Container برای یافتن کلاس‌هایی که IViewModel را در اسمبلی جاری پیاده سازی کرده‌اند، استفاده شده است. متد NameBy، سبب می‌شود که بتوان به این نوع‌های یافت شده از طریق نام کلاس‌های متناظر دسترسی یافت.


اتصال خودکار ViewModelها به Viewهای برنامه

using System.Windows.Controls;
using StructureMap;

namespace DI07.Core
{
    /// <summary>
    /// Stitches together a view and its view-model
    /// </summary>
    public static class ViewModelFactory
    {
        public static void WireUp(this ContentControl control)
        {
            var viewName = control.GetType().Name;
            var viewModelName = string.Concat(viewName, "Model"); //قرار داد نامگذاری ما است
            control.Loaded += (s, e) =>
            {
                control.DataContext = ObjectFactory.GetNamedInstance<IViewModel>(viewModelName);
            };
        }
    }
}
اکنون که کار علامتگذاری ViewModelها انجام شده و همچنین IoC Container ما می‌داند که چگونه باید آن‌ها را در اسمبلی جاری جستجو کند، مرحله بعدی، ایجاد کلاسی است که از این تنظیمات استفاده می‌کند. در کلاس ViewModelFactory، متد WireUp، وهله‌ای از یک View را دریافت کرده، نام آن‌را استخراج می‌کند و سپس بر اساس قراردادی که در ابتدای بحث وضع کردیم، نام ViewModel متناظر را یافته و سپس زمانیکه این View بارگذاری می‌شود، به صورت خودکار DataContext آن‌را به کمک StructureMap وهله سازی می‌کند. این وهله سازی به همراه تزریق خودکار وابستگی‌ها در سازنده کلاس ViewModel نیز خواهد بود.


استفاده از کلاس ViewModelFactory

در ادامه کدهای TestView و پنجره اصلی برنامه را مشاهده می‌کنید:

<UserControl x:Class="DI07.Views.TestView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <TextBlock Text="{Binding Data}" />
    </Grid>
</UserControl>


<Window x:Class="DI07.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Views="clr-namespace:DI07.Views"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Views:TestView />
    </Grid>
</Window>
در فایل Code behind مرتبط با TestView تنها کافی است سطر فراخوانی this.WireUp اضافه شود تا کار تزریق وابستگی‌ها، وهله سازی ViewModel متناظر و همچنین مقدار دهی DataContext آن به صورت خودکار انجام شود:
using DI07.Core;

namespace DI07.Views
{
    public partial class TestView
    {
        public TestView()
        {
            InitializeComponent();
            this.WireUp(); //تزریق خودکار وابستگی‌ها و یافتن ویوو مدل متناظر
        }
    }
}

دریافت پروژه کامل این قسمت
  DI07.zip
نظرات مطالب
بررسی برخی تغییرات در Angular 8
TypeScript 3.4.x Support
انگیولار 8، از (3.4) typescript و نگارش‌های بالاتر پشتیبانی می‌کند. اگر می‌خواهیم از انگیولار 8 برای App ‌های جدید استفاده کنیم، نیاز است typescript را به نگارش 3.4 و یا بالاتر ارتقاء دهیم.

Ivy Rendering Engine
یکی از مهمترین و مورد انتظارترین ویژگی‌های انگیولار 8، موتور IVY می‌باشد. IVY یک Angular Compiler جدید می‌باشد و هم چنین یک ابزار که به عنوان یک rendering pipeline جدید عمل می‌کند. مزیت Ivy این است که به طور قابل توجهی bundle‌های کوچکی را تولید می‌کند (سایز bundle‌ها را کاهش میدهد)  و همچنین به آسانی می‌تواند کامپایل سریعی را انجام دهد. بنابراین Ivy، اساس نوآوری در دنیای انگیولار می‌باشد. Ivy در انگیولار 8 به صورت پیش نمایشی می‌باشد. هدف اصلی این نسخه این است که بازخورد‌ها را از جامعه توسعه دهندگان انگیولار، مرتبط با Ivy دریافت کند. پیشنهاد شده است که در این روزها از Ivy برای حالت ارائه‌ی نهایی (Production) استفاده نشود.


در ngconf  سال  2019، (Brad Green)، هدایت کننده فنی تیم انگیولار گفت که در صورت استفاده از Ivy، از مزایای زیر برخوردار هستیم: 

  • کامپایل سریعتری را فراهم می‌کند (انتشار در انگیولار  9) 
  • بررسی type  در قالب‌ها، خیلی بیشتر بهبود یافته است؛ به‌گونه‌ای که می‌توان خطاهای بیشتری را در زمان build گرفت که باعث می‌شود کاربران در زمان runtime به آن خطاها برخورد نکنند (انتشار در انگیولار 9). 
  • bundle‌های با سایز کوچکتری در مقایسه با سایز bundle‌های کامپایل شده‌ی جاری 
  • کد‌های تولید شده توسط  Angular compiler، بسیار آسان‌تر، برای خواندن و درک انسان است. 
  • آخرین و مهمترین ویژگی مورد علاقه من این است که می‌توان قالب‌ها (templates) را debug کرد. من یقین دارم که این ویژگی توسط تعداد زیادی از توسعه دهندگان مورد توجه قرار خواهد گرفت .
همانطور که در متن بالا گفته شده است اگر بخواهید در یک پروژه‌ی انگیولار، Ivy  را شامل کنید، علاوه بر حالت گفته شده‌ی در متن‌، می‌توانید به صورت دستی تنظیم بالا را به پروژه‌ی انگیولار اضافه کنید (بعد از ارتقاء به انگیولار 8). پیشنهاد شده‌است که اگر می‌خواهیم از Ivy  در Application ‌ها استفاده کنیم، Application را در حالت debug، همراه با AOT compilation اجرا کنید:
ng serve --aot

Bye Bye @angular/http
از نگارش 8 انگیولار، پشتیبانی از angular/http@ متوقف می‌شود. تا نگارش 7 انگیولار، امکان استفاده‌ی از angular/http@ برای ما فراهم بود؛ اما استفاده‌ی از angular/http@ منسوخ شده بود و در نگارش 4 انگیولار یک فراخوانی امن و کارآمد HTTP را با استفاده از  angular/common/http@  فراهم کردند. 

PNPM Support
در نگارش 8 انگیولار، پشتیبانی از یک package manager جدید به نام PNPM وجود دارد که شامل NPM و Yarn می‌باشد.

Support for New Builders/Architect API
نگارش جدید Angular CLI  این اجازه را به ما می‌دهد که از نسخه‌ی جدید Builders که به عنوان Architect API شناخته می‌شود، استفاده کنیم. انگیولار از Builders API برای اجرای  عملیاتی مثل server, build, test, lint و e2e استفاده می‌کند. در ضمن می‌توانیم از builders در فایل angular.json استفاده کنیم: 
"projects": {  
  "app-name": {  
    "architect": {  
      "build": {  
        "builder": "@angular-devkit/build-angular:browser",  
      },  
      "serve": {  
        "builder": "@angular-devkit/build-angular:dev-server",  
      },  
      "test": {  
        "builder": "@angular-devkit/build-angular:karma",  
      },  
      "lint": {  
        "builder": "@angular-devkit/build-angular:tslint",  
      },  
      "e2e": {  
        "builder": "@angular-devkit/build-angular:protractor",  
      }  
    }  
  }  
}
مطالب
یک دست سازی ی و ک دریافتی در صفحات وب

با استفاده از jQuery ، تحت نظر قرار دادن ورودی‌های کاربران در تمام فیلدهای ورودی صفحه کار ساده‌ای است؛ اما جایگزینی مثلا ی فارسی با ی عربی و برعکس درست در لحظه‌ی تایپ آن‌ها کار ساده‌ای نیست و هر مرورگر روش خاص خودش را دارد و بعضی‌ها هم اصلا اجازه‌ی تغییر رخدادهای رسیده را نمی‌دهند.
اسکریپت زیر کار یک دست سازی ی و ک دریافتی در صفحات وب را انجام می‌دهد (برای مثال اگر کاربر ی تایپ کند به صورت خودکار به ی تبدیل می‌شود):
// <![CDATA[
function substituteCharInFireFox(charCode, e) {
var keyEvt = document.createEvent("KeyboardEvent");
keyEvt.initKeyEvent("keypress", true, true, null, false, false, false, false, 0, charCode);
e.target.dispatchEvent(keyEvt);
e.preventDefault();
}

function substituteCharInChrome(charCode, e) {
//it does not work yet! /*$.browser.webkit*/
//https://bugs.webkit.org/show_bug.cgi?id=16735
var keyEvt = document.createEvent("KeyboardEvent");
keyEvt.initKeyboardEvent("keypress", true, true, null, false, false, false, false, 0, charCode);
e.target.dispatchEvent(keyEvt);
e.preventDefault();
}

function insertAtCaret(myValue, e) {
var obj = e.target;
var startPos = obj.selectionStart;
var endPos = obj.selectionEnd;
var scrollTop = obj.scrollTop;
obj.value = obj.value.substring(0, startPos) + myValue + obj.value.substring(endPos, obj.value.length);
obj.focus();
obj.selectionStart = startPos + myValue.length;
obj.selectionEnd = startPos + myValue.length;
obj.scrollTop = scrollTop;
e.preventDefault();
}

$(document).ready(function () {
$(document).keypress(function (e) {

var keyCode = e.keyCode ? e.keyCode : e.which;
var arabicYeCharCode = 1610;
var persianYeCharCode = 1740;
var arabicKeCharCode = 1603;
var persianKeCharCode = 1705;

if ($.browser.msie) {
switch (keyCode) {
case arabicYeCharCode:
event.keyCode = persianYeCharCode;
break;
case arabicKeCharCode:
event.keyCode = persianKeCharCode;
break;
}
}
else if ($.browser.mozilla) {
switch (keyCode) {
case arabicYeCharCode:
substituteCharInFireFox(persianYeCharCode, e);
break;
case arabicKeCharCode:
substituteCharInFireFox(persianKeCharCode, e);
break;
}
}
else {
switch (keyCode) {
case arabicYeCharCode:
insertAtCaret(String.fromCharCode(persianYeCharCode), e);
break;
case arabicKeCharCode:
insertAtCaret(String.fromCharCode(persianKeCharCode), e);
break;
}
}
});
});
// ]]>
تابع substituteCharInChrome قرار است در نگارش‌های آتی گوگل کروم کار کند! کروم فعلا هر نوع شبیه سازی فشرده شدن کلیدهای صفحه کلید را به صفر ترجمه می‌کند. به همین جهت از روش insertAtCaret در مورد آن استفاده شد. هر دو تابع substituteChar ذکر شده در مورد فایرفاکس و کروم و یا روش ساده IE (با توجه به اینکه keyCode در IE فقط خواندنی نیست)، با اپرا کار نمی‌کنند!

  • دریافت این اسکریپت: (+)
  • نسخه‌ی فشرده شده آن: (+)
  • یک پروژه‌ی ساده ASP.NET نمونه در مورد استفاده از آن: (+)

این اسکریپت با IE، فایرفاکس، اپرا ، کروم گوگل و Safari شرکت اپل سازگار است و تفاوتی هم نمی‌کند که در یک html ساده استفاده شود یا در صفحات ASP ، PHP ، ASP.NET ، JSP یا هر چی!


مطالب مشابه: