مطالب
ارسال چند درخواست به صورت همزمان به ASP.NET Web API 2.x در AngularJS 1.x

 ما در AngularJs آبجکتی را به نام  q$ داریم که برای اجرای توابع به صورت async مفید است و همچنین در استفاده از مقادیر برگشتی از این درخواست‌ها برای پردازش‌های آینده به ما کمک میکند. برای اطلاعات بیشتر در مورد این سرویس به اینجا مراجعه کنید.

در ادامه ما از تابع ()all از q$ برای ترکیب چند شیء promise داخل یک شیء promise، به منظور صدا زدن چند سرویس به صورت یکجا، استفاده میکنیم.


پیاده سازی ASP.NET Web API


قدم اول : Visual Studio  را بازکنید و یک پروژه empty ASP.NET Web API را مطابق شکل زیر ایجاد کنید.


قدم دوم : در داخل پوشه models، کلاسی را با کدهای زیر ایجاد کنید:
using System.Collections.Generic;
 
namespace NG_Combine_Multiple_Promises.Models
{
    public class Courses
    {
        public int CourseId { get; set; }
        public string CourseName { get; set; }
    }
    public class CourseDatabase : List<Courses>
    {
        public CourseDatabase()
        {
            Add(new Courses() { CourseId=1,CourseName="الکترونیک"});
            Add(new Courses() { CourseId = 2, CourseName = "ریاضی 2" });
            Add(new Courses() { CourseId = 3, CourseName = "طراحی نرم افزار" });
        }
    }
 
    public class Student
    {
        public int StudentId { get; set; }
        public string Name { get; set; }
        public string AcadmicYear { get; set; }
    }
 
    public class StudentDatabase : List<Student>
    {
        public StudentDatabase()
        {
            Add(new Student() {StudentId=101,Name="محمد علوی", 
                               AcadmicYear="اول" });
            Add(new Student() { StudentId = 102, Name = "طاهره موسوی", 
                               AcadmicYear = "دوم" });
            Add(new Student() { StudentId = 103, Name = "علی عباسی", 
                               AcadmicYear = "سوم" });
            Add(new Student() { StudentId = 104, Name = "جواد نوری", 
                               AcadmicYear = "اول" });
            Add(new Student() { StudentId = 105, Name = "محسن خدایی", 
                               AcadmicYear = "دوم" });
            Add(new Student() { StudentId = 106, Name = "علی کاظمی", 
                               AcadmicYear = "سوم" });
            Add(new Student() { StudentId = 107, Name = "زهرا مقدم", 
                               AcadmicYear = "اول" });
            Add(new Student() { StudentId = 108, Name = "لاله فکور", 
                               AcadmicYear = "دوم" });
            Add(new Student() { StudentId = 109, Name = "علی نوروزی", 
                               AcadmicYear = "چهارم" });
        }
    }
     
}

کد بالا شامل موجودیت‌های Courses و Student است و کلاس‌های CourseDatabase و StudentDatabase به ترتیب برای ذخیره این موجودیت‌ها است.


قدم سوم :  بسته‌ی نیوگت Microsoft.AspNet.WebAPi.Cors را با استفاده از NuGet Package Manager، به منظور فعال سازی امکان صدا زدن این وب سرویس از دامنه‌های مختلف، به پروژه اضافه کرده و کد زیر را در کلاس WebApiCofig در پوشه App_Start قرار دهید.

config.EnableCors();


قدم چهارم : دو کنترل از نوع Web API 2 Empty را با نام‌های CourseAPIController و StudentAPIController ایجاد کرده و کدهای زیر را در آنها قرار دهید.

CourseAPIController.cs 

[EnableCors("*","*","*")]
public class CourseAPIController : ApiController
{
    [Route("Courses")]
    public IEnumerable<Courses> Get()
    {
        return new CourseDatabase();
    }
}

StudentAPIController.cs 

[EnableCors("*", "*", "*")]
public class StudentAPIController : ApiController
{
    [Route("Students")]
    public IEnumerable<Student> Get()
    {
        return new StudentDatabase();
    }
}


استفاده از Angular $q.all  

قدم اول : پروژه‌ی جدیدی را از نوع Empty ASP.NET در همین solution اضافه کرده و ارجاعات jQuery, Bootstrap و AngularJS را با استفاده از NuGet Package manager  مانند زیر اضافه کنید:

Install-Package jQuery
Install-Package bootstrap
Install-Package angularjs


قدم دوم : پوشه‌ایی را به نام MyScripts ایجاد کرده و درون آن فایل javascript  زیر را با نام logic.js اضافه کنید: 

var app = angular.module('mymodule', []);

//سرویسی برای بازگرداندن لیست دروس
app.service('courseService', function ($http) {
    this.get = function () {
        var response = $http.get("http://localhost:11696/Courses");
        return response;
    };
});

//سرویسی برای بازگرداندن لیست دانشجویان
app.service('studentService', function ($http) {
    this.get = function () {
        var response = $http.get("http://localhost:11696/Students");
        return response;
    };
});

//تعریف کنترلر
app.controller('ctrl', function ($scope, $q, courseService, studentService) {

    $scope.Courses = [];
    $scope.Students = [];
    loadData();

    /**/
    function loadData() {
        var promiseCourse = courseService.get();
        var promiseStudent = studentService.get();

        $scope.combineResult = $q.all([
            promiseCourse,
            promiseStudent
        ]).then(function (resp) {
            $scope.Courses = resp[0].data;
            $scope.Students = resp[1].data;
        });
    }
});
توضیحات: تابعq$.all لیستی از promise هایی را که  توسط courseService.get و studentService.get بدست آمده‌اند، گرفته و وقتی تمام promise‌ها تمام شدند، قسمت ()then آن اجرا میشود. 

قدم سوم:  فایل html ایی را با نام DataPage در پوشه‌ی view با کد زیر ایجاد کنید: 
<!DOCTYPE html>
<html ng-app="mymodule">
<head>
    <title></title>
    <meta charset="utf-8" />
    <link href="../Content/bootstrap.min.css" rel="stylesheet" />
    <script src="../Scripts/jquery-3.2.1.min.js"></script>
    <script src="../Scripts/angular.min.js"></script>
    <script src="../MyScripts/logic.js"></script>
</head>
<body ng-controller="ctrl">
       <div class="container">
        <h1 class="h1">دروس</h1>
        <table class="table table-striped table-bordered table-condensed">
            <thead>
                <tr>
                    <td class="text-center">کد درس</td>
                    <td class="text-center">نام درس</td>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="Course in Courses">
                    <td class="text-center">{{Course.CourseId}}</td>
                    <td class="text-center">{{Course.CourseName}}</td>
                </tr>
            </tbody>
        </table>
        <hr />
        <h1 class="h1">دانشجویان</h1>

        <table class="table table-striped table-bordered table-condensed">
            <thead>
                <tr>
                    <td class="text-center">کد دانشجویی</td>
                    <td class="text-center">نام و نام خانوادگی</td>
                    <td class="text-center">سال دانشجویی</td>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="Student in Students">
                    <td class="text-center">{{Student.StudentId}}</td>
                    <td class="text-center">{{Student.Name}}</td>
                    <td class="text-center">{{Student.AcadmicYear}}</td>
                </tr>
            </tbody>
        </table>
    </div>
</body>
</html>

خروجی نهایی پروژه به شکل زیر خواهد بود:

مطالب
Vue.js - نحوه‌ی استفاده از list item ها و تخصیص item - قسمت چهارم
در این قسمت به بحث item list‌‌ها پرداخته می‌شود. روند کلی بدین صورت است که ابتدا یک آرایه را ایجاد کرده (با مقادیر مشخص) و سپس درون تگ مورد نظری از صفحه، آرایه را فراخوانی می‌کنیم.
برای این منظور ابتدا یک vue جدید را ساخته و سپس آرایه مورد نظر را تعریف کرده و آیتم‌های آرایه را مشخص می‌کنیم. به صورت زیر:
     var dotnettips = new Vue({
         el: '#dotnettips',
         data: {
            items: [
                  { message: 'one' },
                  { message: 'two' }
    ]
  }
});
در کد بالا یک ویژگی با نام dotnettips تعریف شده و مقادیری به آن اختصاص داده شده است.
حال زمان آن فرارسیده است تا بدنه اصلی ساختار صفحه را بنویسیم.
<html>
    <body>
    <ul id="dotnettips">
       <li v-for="item in items">
           {{ item.message }}
       </li>
    </ul>
  
    <script src="https://unpkg.com/vue@2.2.6">
    </script>

    <script type="text/javascript">
         var dotnettips = new Vue({
         el: '#dotnettips',
         data: {
            items: [
                  { message: 'one' },
                  { message: 'two' }
            ]
          }
        });
        </script>      
        </body>
</html>
برای نمایش خروجی کار به صورت دلخواه، ابتدا یک تگ ul و درون آن تگ li را ایجاد کردیم و سپس با استفاده از دستور v-for، اقدام به فراخوانی list item مورد نظر کردیم و سپس ویژگی مورد نظر را که همان item.message می‌باشد، درون علامت {{ }} قرار دادیم، تا خروجی نهایی به نمایش درآید.
 .حال با اجرای کد فوق تمامی آیتم‌های مورد نظر روی صفحه به نمایش در می‌آیند 
.دقت نمائید که کدهای فوق و بدنه اسکریپت به دلخواه نوشته شده‌است و شما طبق نیاز خود می‌توانید آن‌ها را تغییر دهید
مطالب
آموزش فایرباگ - #4 - JavaScript Development
در قسمت قبل با توابع خط فرمان آشنا شدیم . در این قسمت با توابع کنسول آشنا خواهیم شد .

فایرباگ یک متغییر عمومی به نام console دارد که به همه‌ی صفحات باز شده در فایرفاکس اضافه می‌کند . این شیء متدهایی دارد که بوسیله آن‌ها می‌توانیم عملیاتی در برنامه مان انجام داده و اطلاعاتی را در کنسول چاپ کنیم .

بعضی از این متدها عملکردی مشابه متدهای خط فرمان ( که در قسمت قبل شرح داده شدند ، ) دارند که از توضیح مجدد آن‌ها اجتناب می‌کنیم .

توابع کنسول - Console API :

توجه : همانند قسمت قبل ، در این قسمت هم برای همراه شدن با تست‌ها ، کد صفحه‌ی زیر را ذخیره کنید و برای اجرای کدها ، آن‌ها را در قسمت خط فرمان ( در تب کنسول ) قرار بدهید و دکمه‌ی Run ( یا Ctrl + Enter ) را بزنید .
<input type="button" onclick="startTrace('Some Text')" value="startTrace" />
<input type="button" onclick="startError()" value="test Error" />

<script type="text/javascript">
    function startTrace(str) {
        return method1(100, 200);
    }
    function method1(arg1, arg2) {
        return method2(arg1 + arg2 + 100);
    }
    function method2(arg1) {
        var var1 = arg1 / 100;
        return method3(var1);
    }
    function method3(arg1) {
        console.trace();
        var total = arg1 * 100;
        return total;
    }

    function testCount() {
        // do something
        console.count("testCount() Calls Count .");
    }

    function startError() {
        testError();
    }

    function testError() {
        var errorObj = new Error();
        errorObj.message = "this is a test error";
        console.exception(errorObj);
    }

    function testFunc() {
        var t = 0;
        for (var i = 0; i < 100; i++) {
            t += i;
        }
    }
</script>
  • console.log(object[,object,...])

    این دستور یک پیغام در کنسول چاپ می‌کند .
    console.log("This is a log message!");
    نتیجه :



    این دستور را می‌توانیم به شکل‌های مختلفی فراخوانی کنیم .
    مثلا :
    console.log(1 , "+" , 2 , "=", (1+2));
    نتیجه :


    در این دستور می‌توانیم از چند حرف جایگزین هم استفاده کنیم .


    مثال :

    console.log("Firebug 1.0 beta was %s in December %i.","released",2006);
    نتیجه :


    عملکرد 3 جایگزین نخست با توجه با مثال قبل مشخص شد . پس به سراغ جایگزین %o و %c می‌رویم .
    اگر در رشته‌ی مورد نظر ، یک شیء ( تابع ، آرایه ، ... ) برای جایگزین %o ارسال کنیم ، در خروجی آن شیء بصورت لینک نمایش داده می‌شود که با کلیک بروی آن ، فایرباگ آن شیء را در تب مناسبش Inspect می‌کند .
    مثال :
    console.log("this is a test functin : %o",testFunc);

    نتیجه :



    و زمانی که بروی لینک testFunc کلیک کنیم :



    یک ترفند : بوسیله جایگزین %o توانستیم به تابع مورد نظر لینک بدهیم . اگر بجای جایگزین %o از %s استفاده کنیم ، می‌توانیم بدنه‌ی تابع را ببینیم :
    console.log("this is a test functin : %s",testFunc);
    نتیجه :




    توسط جایگزین %c هم می‌توانید خروجی را فرمت کنید .

    console.log("%cThis is a Style Formatted Log","color:green;text-decoration:underline;");

    نتیجه :


  • console.debug(object[, object, ...])
  • console.info(object[, object, ...])
  • console.warn(object[, object, ...])
  • console.error(object[, object, ...])

    مشابه با دستور log عمل می‌کنند با این تفاوت که خروجی را با استایل متفاوتی نمایش می‌دهند .
    همچنین هر یک از این دستورات ، توسط دکمه‌های همنام در کنسول قابل فیلتر شدن هستند .



  • console.assert(expression[, object, ...])

    چک می‌کند که عبارت ارسال شده true هست یا نه . اگر true نبود ، پیغام وارد شده را چاپ و یک استثناء ایجاد می‌کند .
    console.assert(1==1,"this is a test error");
    console.assert(1!=1,"this is a test error");

    نتیجه :



  • console.clear()
  • console.dir(object)
  • console.dirxml(node)
  • console.profile([title])
  • console.profileEnd()

  • این توابع معادل توابع همنامشان در خط فرمان هستند که در قسمت قبل با عملکردشان آشنا شدیم .

  • console.trace()

    با این متد می‌توانید پی ببرید که از کجا و توسط چه متدهایی برنامه به قسمت trace رسیده . برای درک بهتر مجددا اسکریپت صفحه‌ی تست این مقاله را بررسی کنید ( جایی که متد trace قرار داده شده است ) .
    اکنون صفحه‌ی تست را باز کنید و بروی دکمه‌ی startTrace کلیک کنید . خروجی ظاهر شده در کنسول را از پایین به بالا بررسی کنید .


    حتما متوجه شدید که متد method3 چگونه در کدهایمان فراخوانی شده است !؟
    ابتدا با کلیک بروی دکمه‌ی startTrace ، متد startTrace اجرا شده و به همین ترتیب متد startTrace متد method1 ، متد method1 هم متد method2 و در نهایت method2 متد method3 را فراخوانی کرده است .
    دستور trace زمانی که در حال بررسی کدهای برنامه نویسان دیگر هستید ، بسیار می‌تواند به شما کمک کند .

  • console.group(object[, object, ...])

    با این دستور می‌توانید لاگ‌های کنسول را بصورت تو در تو گروه بندی کنید .
    console.group("Group1");
    console.log("Log in Group1");
    console.group("Group2");
    console.log("Log in Group2");
    console.group("Group3");
    console.log("Log in Group3");
    نتیجه :



  • console.groupCollapsed(object[, object, ...])

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

  • console.groupEnd()

    به آخرین گروه بندی ایجاد شده خاتمه می‌دهد .

  • console.time(name)

    یک تایمر با نام داده شده ایجاد می‌کند . زمانی که نیاز دارید زمان طی شده بین 2 نقطه را اندازه گیری کنید ، این تابع مفید خواهد بود .

  • console.timeEnd(name)

    تایمر همنام را متوقف و زمان طی شده را چاپ می‌کند .
    console.time("TestTime");
    var t = 1;
    for (var i = 0; i < 100000; i++) { t *= (i + t) }
    console.timeEnd("TestTime");
    نتیجه :


  • console.timeStamp()

    توضیحات کامل را از اینجا دریافت کنید .

  • console.count([title])

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


  • console.exception(error-object[, object, ...])

    یک پیغام خطا را به همراه ردیابی کامل اجرای کدها تا زمان رویداد خطا ( مانند متد trace ) چاپ می‌کند .
    در صفحه‌ی تست این متد را اجرا کنید :
    startError();
    نتیجه :

     توجه کنید که ما برای مشاهده‌ی عملکرد صحیح این دستور ، آن را در تابع testError قرار دادیم و بوسیله تابع startError آن فراخوانی کردیم .

  • console.table(data[, columns])

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


    برای اطلاعات بیشتر به اینجا مراجعه کنید .

منابع :
مطالب
بخش سوم - بررسی امکانات و کدنویسی در کامپایلر Svelte
در بخش‌های قبل تا حدودی با کامپایلر Svelte و ساختار فایل‌های آن آشنا شدیم. در این بخش با چند مثال قصد دارم امکاناتی را که Svelte در اختیارمان قرار میدهد، شرح دهم. 

Dynamic attributes : 
در بخش قبل دیدیم که با استفاده از علامت ( آکولاد {} ) میتوانیم مقادیر موجود در تگ اسکریپت را در html خود رندر کنیم. ولی از این علامت میتوان برای مقدار دهی attribute‌ها هم استفاده کرد. 
<script>
let src = 'https://svelte.dev/tutorial/image.gif';
let name = 'Rick Astley';
</script>

<img src={src} alt="{name} dancing">
اگر این کد را در بدنه کامپوننت خود یعنی همان فایل App.svelte قرار دهیم، به درستی کار خواهد کرد و مقدار‌های متغیر‌های src و name، در تگ img ما قرار خواهند گرفت. چند نکته در اینجا وجود دارد که بهتر است به آنها اشاره کنم.

  • نکته اول : اگر در تگ img مقدار alt را وارد نکنیم و یا alt در این تگ وجود نداشته باشد، یک هشدار توسط کامپایلر svelte برای ما با عنوان <img> element should have an alt attribute> ایجاد میشود. زمان ساخت یک برنامه بسیار مهم است تا قوانین نوشتن یک کد html خوب را رعایت کنیم تا برای تمامی کاربران احتمالی برنامه قابل استفاده باشد. در همین مثال با ایجاد یک هشدار Svelte تلاش میکند که ما را از اشتباه در نوشتن کد html مطلع سازد.

  • نکته دوم : اگر نام یک آبجکت تعریف شده و یک attribute، برابر باشد میتوانیم از نسخه کوتاه شده یا Shorthand attributes در svelte استفاده کنیم. به طور مثال در مثال بالا میتوانیم از کد زیر در خط 6 استفاده کنیم.
<img {src} alt="{name} dancing">


Nested components :
همانطور که قبلا اشاره کرده بودم، همه‌چیز در svelte از کامپوننت‌ها تشکیل میشود. در یک برنامه واقعی درست نیست که تمامی کد برنامه را مستقیما در کامپوننت اولیه برنامه بنویسیم. به جای آن بهتر است هر بخش از وبسایت، کامپوننت مجزایی داشته باشد تا کدها و استایل‌ها و html ما نظم و خوانایی بیشتری پیدا کنند.
یک فایل دیگر را در کنار کامپوننت App.svelte که در بخش قبلی ایجاد کرده بودیم، به نام Nested.svelte ایجاد کنید و در آن کد زیر را قرار دهید.
<script>
  export let siteName = "dotnettips";
</script>

<p>this is a nested component for third tutorial on {siteName}</p>
در این مرحله ما یک کامپوننت جدید را ایجاد کردیم که برای نمایش آن باید به App.svelte اضافه شود. برای انجام اینکار محتوای App.svelte را به کد زیر تغییر دهید.
<script>
  import Nested from "./Nested.svelte";

  export let name;
</script>

<h1>Hello {name}!</h1>

<Nested siteName="dotnettips.info" />
که در نهایت چنین خروجی خواهیم داشت. 
 Hello world!

this is a nested component for third tutorial on dotnettips.info


در مثال بالا ما یک کامپوننت جدید را ایجاد کرده و از طریق دستور import به App.svelte اضافه کردیم. نکته‌ای که در اینجا وجود دارد، نحوه مقدار دهی props در کامپوننت‌ها است. اگر به خط 9 دقت کنیم، کامپوننت ما از طریق تگ جدیدی با نام (Nested) به بدنه html برنامه اضافه شده است که یک attribute به نام siteName دارد. siteName متغیر export شده در کامپوننت Nested.svelte است که در کامپوننت‌ها به این صورت مقدار دهی میشود. قبلا نحوه مقدار دهی این خصیصه‌ها را در فایل‌های جاوا اسکریپت مشاهده کرده بودیم. نکته دیگری که باید به آن دقت داشت این است که خصیصه siteName مقدار پیش فرض dotnettips را در Nested.svelte به خود اختصاص داده بود. به همین جهت اگر ما siteName را هنگام استفاده از کامپوننت مقدار دهی نکنیم، از مقدار پیش فرض خود استفاده خواهد کرد. ولی اینجا ما با مقدار دهی آن، siteName را به dotnettips.info تغییر داده‌ایم.

نکته مهم : دقت داشته باشید کامپوننت‌های شما همیشه باید با حروف بزرگ شروع شوند؛ به طور مثال در صورت نوشتن <nested/> محتوای کامپوننت نمایش داده نخواهد شد. svelte، از طریق زیر نظر گرفتن حروف کوچک و بزرگ در ابتدای تگ‌ها، بین تگ‌های html و کامپوننت‌ها تمایز قائل میشود.



Spread  props :

تا اینجا به صورت خلاصه با props یا خصیصه‌ها آشنا شده‌اید و دیدیم که با export کردن یک متغیر در یک کامپوننت، میتوانیم آن را هنگام استفاده مقدار دهی نماییم. برای اینکه تمرینی هم باشد با توجه به مطالبی که تاکنون گفته شده، پروژه‌ی جدیدی را ایجاد کنید و محتوای App.svelte را مانند کد زیر تغییر دهید.

<script>
import Info from './Info.svelte';

const pkg = {
name: 'svelte',
version: 3,
speed: 'blazing',
website: 'https://svelte.dev'
};
</script>

<Info name={pkg.name} version={pkg.version} speed={pkg.speed} website={pkg.website}/>

همانطور که در خط دوم کد می‌بینید، کامپوننتی به نام Info.svelte به این بخش اضافه شده‌است. این کامپوننت را با محتوای زیر ایجاد نمایید:

<script>
export let name;
export let version;
export let speed;
export let website;
</script>

<p>
The <code>{name}</code> package is {speed} fast.
Download version {version} from <a href="https://www.npmjs.com/package/{name}">npm</a>
and <a href={website}>learn more here</a>
</p>

اگر برنامه را اجرا کنید یک چنین خروجی را مشاهده خواهید کرد: 

 The svelte  package is  blazing  fast. Download version  3  from  npm  and  learn more here
در این مثال در کامپوننت info.svelte حدودا تعداد زیادی متغیر export شده داریم که دقیقا همنام با آنها در App.svelte یک آبجکت به نام pkg مقدار دهی شده‌است (خط 4-9). در این شرایط نیازی به نوشتن تک تک خصیصه‌ها مانند کاری که در خط 12 کردیم نیست. خیلی ساده میتوانیم از امکانات ES6 برای destruct کردن این آبجکت و ست کردن این خصیصه‌ها استفاده کنیم؛ به این صورت : 
<Info {...pkg}/>



مروری کوتاه بر مدیریت Event ها  در svelte:
قدرت اصلی svelte، واکنش پذیر بودن آن است. به این معنی که همیشه DOM را با وضعیت یا state برنامه هماهنگ نگه میدارد. یکی از مواردی که بطور مثال این امکان را به خوبی نمایش میدهد، event‌ها هستند. 
به مثال زیر توجه کنید:
<script>
  let count = 0;

  function handleClick() {
    count += 1;
  }
</script>

<p>Count : {count}</p>
<button on:click={handleClick}>
  Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
در مثال بالا در خط 10، یک button را ایجاد کردیم که به متد click آن یک function اختصاص داده شده که در خط 4 تعریف کرده بودیم. برای bind کردن یک event در svelte از on: استفاده میکنیم. البته دقت کنید که در خط 10، نام function بدون پرانتز نوشته شده‌است؛ چرا که ما قصد اجرای آن را نداریم و صرفا میخواهیم این فانکشن پس از کلیک شدن بر روی button اجرا شود. در خط 5 هم در بدنه فانکشن خود که پس از هر کلیک اجرا خواهد شد، یک واحد به متغیر count اضافه میکنیم. در خطوط 9 و 11 هم مقدار count را نمایش داده‌ایم. 
در بخش‌های بعد به جزئیات کار با event‌ها بیشتر میپردازیم.

واکنش پذیری یا Reactivity در svelte :
svelte به صورت خودکار DOM را پس از اینکه وضعیت کامپوننت یا آبجکت‌های شما تغییر کند، آپدیت میکند؛ ولی در این بین چندین حالت وجود دارند که به صورت خودکار svelte از تغییر وضعیت کامپوننت شما آگاه نمیشود. 
عملگر :$
به مثال زیر توجه کنید. 
<script>
let count = 0;
let doubled = count * 2;

function handleClick() {
count += 1;
}
</script>

<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>

<p>{count} doubled is {doubled}</p>
در این مثال در خط سوم متغیر doubled تعریف شده که قرار است دو برابر count را در خود نگه دارد. اگر این کد را اجرا نمایید، متوجه خواهید شد که مقدار double پس از تغییر count، تغییری نخواهد کرد. چرا که بر خلاف سایر فریم ورک‌ها، مانند react برای بهبود performance برنامه، svelte از Virtual-DOM استفاده نمیکند و این امر سبب میشود که کل کدهای کامپوننت ما در هر بار تغییر، در وضعیت بخشی از آن، مجددا اجرا نشود و مستقیما بخش مورد نظر در DOM تغییر کند. این امر سبب شده از نظر performance در کامپوننت‌های پیچیده که به طور مثال از انیمیشن یا visualisation‌ها استفاده میکنند، کامپوننت‌های svelte چندین برابر پرسرعت‌تر از سایر فریم ورک‌های مشابه عمل کند. ولی اگر بخواهیم که مقدار doubled آپدیت شود چه کاری باید کرد؟ 
راهکار اول مقدار دهی doubled در function مرتبط است، چرا که svelte همیشه به عملگر مساوی = در کد جاوا اسکریپت نگاه میکند. ولی این راهکار در مثال بالا منطقی به نظر نمی‌آید چرا که وظیفه متد ما صرفا دو برابر کردن مقدار count است.
راهکار دوم استفاده از عملگر :$  قبل از تعریف متغیر میباشد که به نظر راهکار مناسب‌تری است. پس در کد بالا فقط لازم است خط سوم را به کد زیر تغییر دهیم تا برنامه بدرستی مقدار doubled را پس از تغییر count محاسبه کند. 
$: doubled = count * 2;
به این طریق میتوانیم متغیر خود را وادار کنیم درصورت تغییر مقادیر، در سمت راست مساوی، مقدار doubled را مجددا محاسبه نماید.

استفاده از این عملگر در svelte به تعریف متغیر‌ها محدود نمیشود. ما هر جائیکه نیاز به واکنش پذیری نسبت به کامپوننت‌ها یا متغیر‌های خود داشتیم، میتوانیم از این عملگر استفاده کنیم. به طور مثال برای لاگ کردن اطلاعات، هر بار که مقدار count تغییر کرد میتوانیم از کد زیر استفاده کنیم. 
$: console.log(`the count is ${count}`);
همچنین میتوانیم به آسانی گروهی از فعالیت‌ها را با هم واکنش پذیر کنیم. مثال :
$: {
  console.log(`the count is ${count}`);
  alert(`I SAID THE COUNT IS ${count}`);
}
حتی میتوان از این عملگر قبل از بلاک‌های کد، مانند if یا for استفاده کرد. مثال:
$: if (count >= 10) {
     alert(`count is dangerously high!`);
     count = 9;
}

واکنش پذیری در آرایه‌ها و آبجکت‌ها : 
به مثال زیر توجه کنید:
<script>
  let numbers = [1, 2, 3, 4];

  function addNumber() {
    let newNumber = numbers.length + 1;
    numbers.push(newNumber);
  }

  $: sum = numbers.reduce((t, n) => t + n, 0);
</script>

<p>{numbers.join(' + ')} = {sum}</p>

<button on:click={addNumber}>Add a number</button>

در مثال بالا پس از هر کلیک، یک عدد به آرایه numbers اضافه میشود؛ ولی در خط 11 که این آرایه را نمایش میدهیم، مقدار آن تغییر نخواهد کرد! همانطور که قبلا اشاره کرده بودم svelte برای اینکه متوجه شود تغییری در آبجکت‌های ما صورت گرفته است، به مشاهده عملگر مساوی در کدهای ما میپردازد و چون اینجا در خط 6، ما از متد push آرایه برای افزودن مقداری جدید به آن درحال استفاده هستیم svelte واکنشی به این تغییر ندارد. برای رفع این مشکل دو راهکار وجود دارد. 
راهکار اول استفاده از عملگر مساوی و reassign کردن مقدار آبجکت یا متغیر مورد نظر است به این صورت : 
  function addNumber() {
    let newNumber = numbers.length + 1;
    numbers.push(newNumber);
    numbers = numbers;
  }
راهکار دوم استفاده از امکانات ES6 جاوا اسکریپت است برای افزودن مقدار جدید به آرایه که چون در این روش از مساوی استفاده میکنیم، تغییرات در numbers واکنش پذیر خواهد بود. به این صورت : 
  function addNumber() {
    let newNumber = numbers.length + 1;
    numbers = [...numbers, newNumber];
  }

مروری بر Two way bindings :
فرض کنید قصد داریم که یک input برای دریافت نام در صفحه قرار داده و در متغیری به نام name ذخیره کنیم. سپس این متغیر را در صفحه نشان دهیم. برای انجام اینکار حدودا با توجه به مطالبی که تا الان آموخته‌ایم میتوان کد زیر را تولید کرد : 
<script>
  let name = "";
  function updateName(event) {
    name = event.target.value;
  }
</script>

<h4>My Name Is {name}</h4>
<input value={name} on:input={updateName} />
در خط 9 یک input به کامپوننت خود اضافه کردیم و مقدار value آن را به متغیر name نسبت دادیم. تا اینجا فقط اگر name تغییری کند آن را در input میتوانیم نمایش دهیم ولی پس از تایپ در این input به صورت خودکار مقدار name آپدیت نمیشود چون ما در این حالت از One way binding درحال استفاده هستیم. به همین جهت یک متد برای آپدیت مقدار name توسط input هم باید مینوشتیم که اگر دقت کنید در کد فوق از ایونت input تگ input در خط 11 به همین منظور استفاده شده‌است. در خط سوم اینبار متد ما یک پارامتر هم به نام event دارد. به طور پیش فرض میتوانیم همیشه از طریق این پارامتر به ایونت آبجکت مبداء که فانکشن را صدا زده است، دسترسی داشته باشیم که خیلی ساده از طریق این ایونت در خط 4 مقدار name را پس تغییر در input آپدیت میکنیم. 
شاید کد بالا کاری که خواستیم را انجام داده باشد. ولی پیاده سازی Two way binding به شکلی که نوشتیم ساده نیست و مشکلات خاص خودش را دارد. خبر خوب این است که svelte این امکان را به صورت توکار محیا کرده است. 
برای اتصال یک attribute به یک متغیر یا آبجکت به صورت دو طرفه از کلمه :bind قبل از نام attribute در svelte استفاده میشود. مثال بالا را اگر با استفاده از این توضیح بازنویسی کنیم، به این کد خواهیم رسید:
<script>
  let name = "";
</script>

<h4>My Name Is {name}</h4>
<input bind:value={name} />
همانطور که مشاهده میکنید دیگر نیازی به نوشتن یک فانکشن مجزا و گرفتن اطلاعات از طریق پارامتر ایونت نیست و به سادگی مقدار value به متغیر name به صورت دو طرفه متصل شده است.


expressing logic :
html امکانی برای پیاده سازی منطق برنامه، برخلاف svelte ندارد. در ادامه با syntax پیاده سازی منطق برنامه در کنار کدهای html در svelte آشنا میشویم. 

If blocks
برای نوشتن If در svelte از if# در میان دو آکولاد {} استفاده میشود و برای پایان دادن به آن از if/ در میاد دو آکولاد. به این صورت : 
{#if condition}
    <!-- you html codes ...  -->
{/if}
به مثال زیر توجه کنید : 
در این مثال قصد داریم پس از کلیک بر روی کلید لاگین، وضعیت کاربر را لاگین شده قرار دهیم و کلید لاگین را مخفی کنیم. سپس کلید دیگری برای خروج از برنامه به نام logout را نمایش دهیم که با کلیک بر روی آن کاربر logout شود و مجددا کلید لاگین نمایش داده شود. برای شبیه سازی این سناریو از کد زیر میتوانیم استفاده کنیم :
<script>
let user = { loggedIn: false };

function toggle() {
user.loggedIn = !user.loggedIn;
}
</script>

{#if user.loggedIn}
<button on:click={toggle}>
Log out
</button>
{/if}

{#if !user.loggedIn}
<button on:click={toggle}>
Log in
</button>
{/if}
کدهای داخل اسکریپت که چندان نیازی به توضیح ندارند و صرفا برای toggle کردن وضعیت کاربر هستند. ولی در خطوط 9 - 13 و 15 - 19 طریقه نوشتن if در svelte را با یک مثال واقعی مشاهده میکنید.
در مثال بالا دو شرط با یک مقدار مشابه true/false نوشته شده است که بهتر بود مانند سایر زبان‌های برنامه نویسی از else در اینجا استفاده میشد. در ادامه با نحوه نوشتن else در svelte آشنا خواهیم شد.
Else blocks
برای نوشتن else در svelte از else: در میاد دو آکولاد {} بین یک block مانند if میتوانیم استفاده کنیم. به این صورت :
{#if condition}
    <!-- you html code when condition is true -->
{:else}
    <!-- you html code when condition is false -->
{/if}
باز نویسی دو if block در مثال بالا با استفاده از else : 
{#if user.loggedIn}
<button on:click={toggle}>
Log out
</button>
{:else}
<button on:click={toggle}>
Log in
</button>
{/if}

همینطور شما میتوانید از else if هم استفاده نمایید. به این صورت : 
{#if condition}
    <!-- you html code when condition is true -->
{:else if condition2}
    <!-- you html code when condition2 is true -->
{:else}
    <!-- you html code when condition and condition2 are false -->
{/if}

نکته تکمیلی : در svelte علامت # همیشه به معنای شروع یک بلاک کد است و علامت / به معنای پایان بلاک. همینطور علامت : نشان دهنده ادامه بلاک کد است. شاید در ابتدا کمی گیج کننده به نظر بیاید ولی در مثال‌های بعدی بیشتر با این علائم آشنا میشویم.

each blocks : 
برای حرکت در میان لیستی از اطلاعات در svelte میتوانیم از each# استفاده نماییم و مانند بلاک if برای خاتمه دادن به آن از each/ استفاده میشود. همینطور از کلمه کلیدی as هم برای دسترسی به هر آیتم در لیست استفاده میشود. به این صورت : 
{#each list as item}
      <!-- you html code per each item in list -->
{/each}
به مثال زیر توجه کنید : 
<script>
let cats = [
{ id: 'J---aiyznGQ', name: 'Keyboard Cat' },
{ id: 'z_AbfPXTKms', name: 'Maru' },
{ id: 'OUtn3pvWmpg', name: 'Henri The Existential Cat' }
];
</script>

<h1>The Famous Cats of YouTube</h1>

<ul>
{#each cats as cat}
<li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
{cat.name}
</a></li>
{/each}
</ul>
در خط 2 ما یک آرایه از گربه‌ها را تعریف کرده ایم و در خط 11 با استفاده از each به ازای هر کدام از آیتم‌های داخل این آرایه یک تگ li ایجاد میکنیم که لینک مرتبط با آن آیتم را نمایش میدهد. البته کد فوق را به شکل دیگری با استفاده از امکانات destructing جاوا اسکریپت هم میتوانستیم بنویسیم. به این صورت : 
<ul>
{#each cats as {id,name}}
<li><a target="_blank" href="https://www.youtube.com/watch?v={id}">
{name}
</a></li>
{/each}
</ul>
در این حالت ابتدا id و name به صورت مجزا destruct شده اند و میتوانیم مانند مثال بالا از آنها بدون نوشتن نام آیتم استفاده کنیم . مانند خط 4 کد بالا.
همینطور در each بلاک‌ها امکان دریافت ایندکس جاری آیتم از طریق آرگومان دوم هم وجود دارد. به این صورت : 
<ul>
{#each cats as { id, name }, i}
<li><a target="_blank" href="https://www.youtube.com/watch?v={id}">
{i + 1}: {name}
</a></li>
{/each}
</ul>
اگر به کد فوق دقت کنید درخط 2 مقدار i ایندکس آیتم جاری آرایه ما یعنی همان cats است.


نکته : در این بخش من سعی کردم تا حدودی به ترتیب بخش آموزشی خود وبسایت Svelte، موارد را بیان کنم؛ ولی با توجه به اینکه شاید دوستان ترجیح بدهند روش آموزشی خود  آن وبسایت که امکان تغییر و نوشتن کد را هم محیا کرده است، امتحان کنند  لینک آن  را به اشتراک میگذارم. 
مطالب
استفاده از کتابخانه‌های ثالث جاوا اسکریپتی در برنامه‌های AngularJS 2.0
هزاران کتابخانه‌ی جاوا اسکریپتی مستقل از AngularJS 2.0 وجود دارند که نیاز است بتوانیم از آن‌ها در برنامه‌های مختلفی استفاده کنیم. در این مطلب، دو روش بارگذاری آن‌ها را بررسی خواهیم کرد.


هدف: استفاده از کتابخانه‌ی jsSHA

می‌خواهیم در یک برنامه‌ی AngularJS 2.0، از کتابخانه‌ی jsSHA استفاده کرده و هش SHA512 یک رشته را محاسبه کنیم.


تامین پیشنیازهای اولیه

می‌توان فایل‌های این کتابخانه را مستقیما از GitHub دریافت و به پروژه اضافه کرد. اما بهتر است این‌کار را توسط npm مدیریت کنیم. به همین جهت فایل package.json آن‌را گشوده و سپس مدخل متناظری را به آن اضافه کنید:
"dependencies": {
    // ...
    "jssha": "^2.1.0",
    // ...
  },
به این ترتیب با اجرای دستور npm install بر روی پوشه‌ی جاری و یا ذخیره‌ی فایل در ویژوال استودیو، کار دریافت خودکار این کتابخانه صورت گرفته و در مسیر node_modules\jssha\src ذخیره می‌شود.


بارگذاری فایل‌های کتابخانه به صورت پویا

یک روش استفاده از این کتابخانه یا هر کتابخانه‌ی جاوا اسکریپتی، افزودن مدخل تعریف آن به صفحه‌ی index.html است:
 <script src="node_modules/jssha/src/sha512.js"></script>
این روش هر چند کار می‌کند، اما با توجه به اینکه AngularJS 2.0 از System.JS برای مدیریت ماژول‌های خود کمک می‌گیرد، می‌تواند با روش پویای ذیل جایگزین شود. برای این منظور ابتدا فایل systemjs.config.js را باز کنید و سپس دو تغییر ذیل را به آن اعمال نمائید:
// map tells the System loader where to look for things
var map = {
    // ...
    'jssha': 'node_modules/jssha/src'
};
 
// packages tells the System loader how to load when no filename and/or no extension
var packages = {
    // ...
    'jssha': { main: 'sha512.js', defaultExtension: 'js' }
};
در اینجا به اشیاء map و packages آن فایل که کار بارگذاری ماژول‌ها را به صورت خودکار انجام می‌دهد، تعاریف جدید jssha را اضافه کرده‌ایم. در قسمت map، مسیر پوشه‌ی فایل‌های js این کتابخانه مشخص شده‌اند و در قسمت packages، نام فایل اصلی مدنظر و پسوندهای آن‌ها ذکر گردید‌ه‌اند.
به این ترتیب هر زمانیکه کار import این کتابخانه صورت گیرد، بارگذاری پویای آن انجام خواهد شد. به علاوه ابزارهای بسته بندی و deploy پروژه هم این فایل را پردازش کرده و به صورت خودکار، کار bundling، فشرده سازی و یکی سازی اسکریپت‌ها را انجام می‌دهند.


استفاده از jsSHA به صورت untyped

پس از دریافت بسته‌های این کتابخانه و مشخص سازی نحوه‌ی بارگذاری پویای آن، اکنون نوبت به استفاده‌ی از آن است. در اینجا منظور از untyped این است که فرض کنیم برای این کتابخانه، فایل‌های typings مخصوص TypeScript وجود ندارند و پس از جستجوی در مخزن کد https://github.com/DefinitelyTyped/DefinitelyTyped نتوانسته‌ایم معادلی را برای آن پیدا کنیم. بنابراین فایل جدید untyped-sha.component.ts را با محتوای ذیل به پروژه اضافه کنید:
import { Component, OnInit } from '@angular/core';
 
var jsSHA = require("jssha"); // ==> loads `sha512.js` file dynamically using `systemjs.config.js` file definitions
//declare var jsSHA: any; // ==> this requires adding <script src="node_modules/jssha/src/sha512.js"></script> to the first page manually.
 
@Component({
    templateUrl: 'app/using-third-party-libraries/untyped-sha.component.html'
})
export class UnTypedShaComponent implements OnInit {
    hash: String;
 
    ngOnInit(): void {
        let shaObj = new jsSHA("SHA-512", "TEXT");
        shaObj.update("This is a test");
        this.hash = shaObj.getHash("HEX");
    }
}
با این قالب untyped-sha.component.html
<h1>SHA-512 Hash / UnTyped</h1>
 
<p>String: This is a test</p>
<p>HEX: {{hash}}</p>
توضیحات
هر زمانیکه فایل‌های typing یک کتابخانه‌ی جاوا اسکریپتی در دسترس نبودند، فقط کافی است از روش declare var jsSHA: any استفاده کنید. در اینجا any به همان حالت استاندارد و بی‌نوع جاوا اسکریپت اشاره می‌کند. در این حالت برنامه بدون مشکل کامپایل خواهد شد؛ اما از تمام مزایای TypeScript مانند بررسی نوع‌ها و همچنین intellisense محروم می‌شویم.
در این مثال در hook ویژه‌ای به نام OnInit، کار ساخت شیء SHA را انجام داده و سپس هش عبارت This is a test محاسبه شده و به خاصیت عمومی hash انتساب داده می‌شود. سپس این خاصیت عمومی، در قالب این کامپوننت از طریق روش interpolation نمایش داده شده‌است.

دو نکته‌ی مهم
الف) اگر از روش declare var jsSHA: any استفاده کردید، کار بارگذاری فایل sha512.js به صورت خودکار رخ نخواهد داد؛ چون ماژولی را import نمی‌کند. بنابراین تعاریف systemjs.config.js ندید گرفته خواهد شد. در این حالت باید از همان روش متداول افزودن تگ script این کتابخانه به فایل index.html استفاده کرد.
ب) برای بارگذاری پویای کتابخانه‌ی jsSHA بر اساس تعاریف فایل systemjs.config.js از متد require کمک بگیرید:
 var jsSHA = require("jssha");
در این حالت باز هم متغیر jsSHA تعریف شده از نوع any است؛ اما اینبار متد require کار بارگذاری خودکار ماژولی را به نام jssha، انجام می‌دهد. این بارگذاری هم بر اساس تعاریف قسمت «بارگذاری فایل‌های کتابخانه به صورت پویا» ابتدای بحث کار می‌کند.


استفاده از jsSHA به صورت typed

کتابخانه‌ی jsSHA در مخزن کد https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/jssha دارای فایل d.ts. مخصوص خود است. برای نصب آن از یکی از دو روش ذیل استفاده کنید:
الف) نصب دستی فایل‌های typings
 npm install -g typings
typings install jssha --save --ambient
توسط خط فرمان، به پوشه‌ی ریشه‌ی پروژه وارد شده و دو دستور فوق را صادر کنید. به این ترتیب فایل‌های d.ts. لازم، به پوشه‌ی typings پروژه اضافه می‌شوند.
ب) تکمیل فایل typings.ts
{
    "ambientDependencies": {
         // ...
        "jssha": "registry:dt/jssha#2.1.0+20160317120654"
    }
}
برای این منظور فایل typings.json را گشوده و سپس سطر جدید فوق را به آن اضافه کنید. اکنون اگر فایل package.json را یکبار دیگر ذخیره کنید و یا دستور npm install را صادر کنید، همان مراحل قسمت الف تکرار خواهند شد.

پس از نصب فایل‌های typings این پروژه، به فایل main.ts مراجعه کرده و مدخل ذیل را به ابتدای آن اضافه کنید:
/// <reference path="../typings/browser/ambient/jssha/index.d.ts" />
اینکار سبب خواهد شد تا intellisense درون ویژوال استودیو بتواند مداخل متناظر را یافته و راهنمای مناسبی را ارائه دهد.

در ادامه فایل جدید typed-sha.component.ts را با محتوای ذیل به پروژه اضافه کنید:
import { Component, OnInit } from '@angular/core';
//import { jsSHA } from "jssha";
import * as jsSHA from "jssha"; // ===> var jsSHA = require("jssha"); // ===> loads `sha512.js` file dynamically using `systemjs.config.js` file definitions
 
@Component({
    templateUrl: 'app/using-third-party-libraries/typed-sha.component.html'
})
export class TypedShaComponent implements OnInit{
    hash: String;
 
    ngOnInit(): void {
        let shaObj = new jsSHA("SHA-512", "TEXT");
        shaObj.update("This is a test");
        this.hash = shaObj.getHash("HEX");
    }
}
محتویات فایل typed-sha.component.html با محتویات فایل untyped-sha.component.html که پیشتر عنوان شد، یکی است.
در اینجا تنها نکته‌ی مهم و جدید نسبت به روش قبل (استفاده از jsSHA به صورت untyped)، روش import این کتابخانه است. روش "import * as jsSHA from "jssha به عبارت var jsSHA = require("jssha") ترجمه می‌شود که در نهایت سبب بارگذاری خودکار فایل‌های jssha بر اساس تعاریف مداخل آن در فایل systemjs.config.js می‌گردد.


کدهای کامل این پروژه را از اینجا می‌توانید دریافت کنید.
مطالب
استفاده از نگارش سوم Google Analytics API در سرویس‌های ویندوز یا برنامه‌های وب
در زمان نگارش این مطلب، آخرین نگارش API مخصوص Google Analytics، نگارش سوم آن است و ... کار کردن با آن دارای مراحل خاصی است که حتما باید رعایت شوند. در غیر اینصورت عملا در یک برنامه‌ی وب یا سرویس ویندوز قابل اجرا نخواهند بود. زیرا در حالت متداول کار با API مخصوص Google Analytics، ابتدا یک صفحه‌ی لاگین به Gmail باز می‌شود که باید به صورت اجباری، مراحل آن را انجام داد تا مشخصات تائید شده‌ی اکانت در حال استفاده‌ی از API، در پوشه‌ی AppData ویندوز برای استفاده‌های بعدی ذخیره شود. این مورد برای یک برنامه‌ی دسکتاپ معمولی مشکل ساز نیست؛ زیرا کاربر برنامه، به سادگی می‌تواند صفحه‌ی مرورگری را که باز شده‌است، دنبال کرده و به اکانت گوگل خود وارد شود. اما این مراحل را نمی‌توان در یک برنامه‌ی وب یا سرویس ویندوز پیگیری کرد، زیرا عموما امکان لاگین از راه دور به سرور و مدیریت صفحه‌ی لاگین به Gmail وجود ندارد یا بهتر است عنوان شود، بی‌معنا است. برای حل این مشکل، گوگل راه حل دیگری را تحت عنوان اکانت‌های سرویس، ارائه داده است که پس از ایجاد آن، یک یک فایل X509 Certificate برای اعتبارسنجی سرویس، در اختیار برنامه نویس قرار می‌گیرد تا بدون نیاز به لاگین دستی به Gmail، بتواند از API گوگل استفاده کند. در ادامه نحوه‌ی فعال سازی این قابلیت و استفاده از آن‌را بررسی خواهیم کرد.


ثبت برنامه‌ی خود در گوگل و انجام تنظیمات آن

اولین کاری که برای استفاده از نگارش سوم Google Analytics API باید صورت گیرد، ثبت برنامه‌ی خود در Google Developer Console است. برای این منظور ابتدا به آدرس ذیل وارد شوید:
سپس بر روی دکمه‌ی Create project کلیک کنید. نام دلخواهی را وارد کرده و در ادامه بر روی دکمه‌ی Create کلیک نمائید تا پروفایل این پروژه ایجاد شود.



تنها نکته‌ی مهم این قسمت، بخاطر سپردن نام پروژه است. زیرا از آن جهت اتصال به API گوگل استفاده خواهد شد.
پس از ایجاد پروژه، به صفحه‌ی آن وارد شوید و از منوی سمت چپ صفحه، گزینه‌ی Credentials را انتخاب کنید. در ادامه در صفحه‌ی باز شده، بر روی دکمه‌ی Create new client id کلیک نمائید.


در صفحه‌ی باز شده، گزینه‌ی Service account را انتخاب کنید. اگر سایر گزینه‌ها را انتخاب نمائید، کاربری که قرار است از API استفاده کند، باید بتواند توسط مرورگر نصب شده‌ی بر روی کامپیوتر اجرا کننده‌ی برنامه، یکبار به گوگل لاگین نماید که این مورد مطلوب برنامه‌های وب و همچنین سرویس‌ها نیست.


در اینجا ابتدا یک فایل مجوز p12 را به صورت خودکار دریافت خواهید کرد و همچنین پس از ایجاد client id، نیاز است، ایمیل آن‌را جایی یادداشت نمائید:


از این ایمیل و همچنین فایل p12 ارائه شده، جهت لاگین به سرور استفاده خواهد شد.
همچنین نیاز است تا به برگه‌ی APIs پروژه‌ی ایجاد شده رجوع کرد و گزینه‌ی Analytics API آن‌را فعال نمود:


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


دادن دسترسی به Client ID ثبت شده در برنامه‌ی Google Analytics

پس از اینکه Client ID سرویس خود را ثبت کردید، نیاز است به اکانت Google Analytics خود وارد شوید. سپس در منوی آن، گزینه‌ی Admin را پیدا کرده و به آن قسمت، وارد شوید:


در ادامه به گزینه‌ی User management آن وارد شده و به ایمیل Client ID ایجاد شده در قسمت قبل، دسترسی خواندن و آنالیز را اعطاء کنید:


در صورت عدم رعایت این مساله، کلاینت API، قادر به دسترسی به Google Analytics نخواهد بود.


استفاده از نگارش سوم Google Analytics API در دات نت

قسمت مهم کار، تنظیمات فوق است که در صورت عدم رعایت آن‌ها، شاید نصف روزی را مشغول به دیباگ برنامه شوید. در ادامه نیاز است پیشنیازهای دسترسی به نگارش سوم Google Analytics API را نصب کنیم. برای این منظور، سه بسته‌ی نیوگت ذیل را توسط کنسول پاورشل نیوگت، به برنامه اضافه کنید:
 PM> Install-Package Google.Apis
PM> Install-Package Google.Apis.auth
PM> Install-Package Google.Apis.Analytics.v3
پس از نصب، کلاس GoogleAnalyticsApiV3 زیر، جزئیات دسترسی به Google Analytics API را کپسوله می‌کند:
using System;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using Google.Apis.Analytics.v3;
using Google.Apis.Analytics.v3.Data;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;

namespace GoogleAnalyticsAPIv3Tests
{
    public class AnalyticsQueryParameters
    {
        public DateTime Start { set; get; }
        public DateTime End { set; get; } 
        public string Dimensions { set; get; } 
        public string Filters { set; get; }
        public string Metrics { set; get; }
    }

    public class AnalyticsAuthentication
    {
        public Uri SiteUrl { set; get; }
        public string ApplicationName { set; get; }
        public string ServiceAccountEmail { set; get; }
        public string KeyFilePath { set; get; }
        public string KeyFilePassword { set; get; }

        public AnalyticsAuthentication()
        {
            KeyFilePassword = "notasecret";
        }
    }

    public class GoogleAnalyticsApiV3
    {
        public AnalyticsAuthentication Authentication { set; get; }
        public AnalyticsQueryParameters QueryParameters { set; get; }

        public GaData GetData()
        {
            var service = createAnalyticsService();
            var profile = getProfile(service);
            var query = service.Data.Ga.Get("ga:" + profile.Id,
                                QueryParameters.Start.ToString("yyyy-MM-dd"),
                                QueryParameters.End.ToString("yyyy-MM-dd"),
                                QueryParameters.Metrics);
            query.Dimensions = QueryParameters.Dimensions;
            query.Filters = QueryParameters.Filters;
            query.SamplingLevel = DataResource.GaResource.GetRequest.SamplingLevelEnum.HIGHERPRECISION;
            return query.Execute();
        }

        private AnalyticsService createAnalyticsService()
        {
            var certificate = new X509Certificate2(Authentication.KeyFilePath, Authentication.KeyFilePassword, X509KeyStorageFlags.Exportable);
            var credential = new ServiceAccountCredential(
                new ServiceAccountCredential.Initializer(Authentication.ServiceAccountEmail)
                {
                    Scopes = new[] { AnalyticsService.Scope.AnalyticsReadonly }
                }.FromCertificate(certificate));

            return new AnalyticsService(new BaseClientService.Initializer
            {
                HttpClientInitializer = credential,
                ApplicationName = Authentication.ApplicationName
            });
        }

        private Profile getProfile(AnalyticsService service)
        {
            var accountListRequest = service.Management.Accounts.List();
            var accountList = accountListRequest.Execute();
            var site = Authentication.SiteUrl.Host.ToLowerInvariant();
            var account = accountList.Items.FirstOrDefault(x => x.Name.ToLowerInvariant().Contains(site));
            var webPropertyListRequest = service.Management.Webproperties.List(account.Id);
            var webPropertyList = webPropertyListRequest.Execute();
            var sitePropertyList = webPropertyList.Items.FirstOrDefault(a => a.Name.ToLowerInvariant().Contains(site));
            var profileListRequest = service.Management.Profiles.List(account.Id, sitePropertyList.Id);
            var profileList = profileListRequest.Execute();
            return profileList.Items.FirstOrDefault(a => a.Name.ToLowerInvariant().Contains(site));
        }
    }
}
در اینجا در ابتدا بر اساس فایل p12 ایی که از گوگل دریافت شد، یک X509Certificate2 ایجاد می‌شود. پسورد این فایل مساوی است با ثابت notasecret که در همان زمان تولید اکانت سرویس در گوگل، لحظه‌ای در صفحه نمایش داده خواهد شد. به کمک آن و همچنین ServiceAccountEmail ایمیلی که پیشتر به آن اشاره شد، می‌توان به AnalyticsService لاگین کرد. به این ترتیب به صورت خودکار می‌توان شماره پروفایل اکانت سایت خود را یافت و از آن در حین فراخوانی service.Data.Ga.Get استفاده کرد.


مثالی از نحوه استفاده از کلاس GoogleAnalyticsApiV3

در ادامه یک برنامه‌ی کنسول را ملاحظه می‌کنید که از کلاس GoogleAnalyticsApiV3 استفاده می‌کند:
using System;
using System.Collections.Generic;
using System.Linq;

namespace GoogleAnalyticsAPIv3Tests
{
    class Program
    {

        static void Main(string[] args)
        {
            var statistics = new GoogleAnalyticsApiV3
            {
                Authentication = new AnalyticsAuthentication
                {
                    ApplicationName = "My Project",
                    KeyFilePath = "811e1d9976cd516b55-privatekey.p12",
                    ServiceAccountEmail = "10152bng4j3mq@developer.gserviceaccount.com",
                    SiteUrl = new Uri("https://www.dntips.ir/")
                },
                QueryParameters = new AnalyticsQueryParameters
                {
                    Start = DateTime.Now.AddDays(-7),
                    End = DateTime.Now,
                    Dimensions = "ga:date",
                    Filters = null,
                    Metrics = "ga:users,ga:sessions,ga:pageviews"
                }
            }.GetData();


            foreach (var result in statistics.TotalsForAllResults)
            {
                Console.WriteLine(result.Key + " -> total:" + result.Value);
            }
            Console.WriteLine();

            foreach (var row in statistics.ColumnHeaders)
            {
                Console.Write(row.Name + "\t");
            }
            Console.WriteLine();

            foreach (var row in statistics.Rows)
            {
                var rowItems = (List<string>)row;
                Console.WriteLine(rowItems.Aggregate((s1, s2) => s1 + "\t" + s2));
            }

            Console.ReadLine();
        }
    }
}

چند نکته
ApplicationName همان نام پروژه‌ای است که ابتدای کار، در گوگل ایجاد کردیم.
KeyFilePath مسیر فایل مجوز p12 ایی است که گوگل در حین ایجاد اکانت سرویس، در اختیار ما قرار می‌دهد.
ServiceAccountEmail آدرس ایمیل اکانت سرویس است که در قسمت ادمین Google Analytics به آن دسترسی دادیم.
SiteUrl آدرس سایت شما است که هم اکنون در Google Analytics دارای یک اکانت و پروفایل ثبت شده‌است.
توسط AnalyticsQueryParameters می‌توان نحوه‌ی کوئری گرفتن از Google Analytics را مشخص کرد. تاریخ شروع و پایان گزارش گیری در آن مشخص هستند. در مورد پارامترهایی مانند Dimensions و Metrics بهتر است به مرجع کامل آن در گوگل مراجعه نمائید:
Dimensions & Metrics Reference

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


برای مطالعه بیشتر
Using Google APIs in Windows Store Apps
How To Use Google Analytics From C# With OAuth
Google Analytic’s API v3 with C#
.NET Library for Accessing and Querying Google Analytics V3 via Service Account
Google OAuth2 C#
مطالب
انتقال دائمی آدرس ها (Permanent Ridirect) در ASP.NET Webform
یکی از مسائلی که همیشه برای وب سایت، از نظر موتور‌های جستجو بسیار مهم است، مقوله SEO Friendly بودن آدرس‌هاست. خوشبختانه در ASP.NET MVC این مقوله به خوبی پوشش داده شده است. برای مثال این قابلیت در ASP.NET Webforms توسط بسته نرم افزاری به نام ASP.NET FriendlyUrls توسط تیم توسعه دهنده ASP.NET ارائه شده است. در این زمینه قبلا آقای کاویانی در همین سایت در صفحه مروری بر قابلیت جدید ASP.NET FriendlyUrls  به این مقوله پرداخته‌اند و با مثال، نحوه‌ی استفاده از این بسته‌ی نرم افزاری را آموزش داده‌اند.
یکی از مسائلی که در ASP.NET Webforms با آن مواجه بودیم انتقال دائمی آدرس‌های صفحات یا همان Permanent Redirect بود.
در واقع زمانیکه شما در حالت عادی از بسته‌ی نرم افزاری مذکور استفاده می‌کنید، این افزونه باعث SEO Friendly شدن آدرس‌های صفحات شما می‌گردد. با در نظر گرفتن اینکه شما مطلب مروری بر قابلیت جدید ASP.NET FriendlyUrls  را مطالعه کرده اید، به فرض مثال کد زیر:
public static class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.EnableFriendlyUrls();
            routes.MapPageRoute("Sitemap", "sitemap.xml", "~/sitemap.aspx");
        }
    }
و رجیستر کردن آن در RouteTable سایت به صورت زیر در فایل Global
protected void Application_Start(object sender, EventArgs e)
{
     RouteConfig.RegisterRoutes(RouteTable.Routes);
}
باعث می‌شود که با زدن آدرس https://www.dntips.ir/sitemap.xml آدرس https://www.dntips.ir/sitemap.aspx لود شود؛ اما در نوار آدرس، همان آدرس sitemap.xml باقی خواهد ماند.
در این روش در صورتیکه کاربر آدرس https://www.dntips.ir/sitemap.aspx را در مرورگر خود تایپ کند باز هم سایت کار می‌کند (آدرس مورد نظر در دسترس است) و فاجعه زمانی شروع می‌شود که موتور جستجو، با محتوی تکراری در سایت در دو آدرس مختلف مواجه شود (پست آقای نصیری را در بهبود SEO در ASP.NET MVC  بررسی کنید) .
یا زمانیکه شما صفحات قدیمی دارید و می‌خواهید آنها را به آدرس‌های جدید منتقل کنید. برای رفع این مشکل طوری‌که هر زمان آدرس قدیمی هم وارد سیستم مسیریابی سایت شود به صورت اتوماتیک به آدرس جدید به صورت دائم منتقل شود، می‌توانید کد بالا را به صورت زیر اصلاح نمایید:
public static void RegisterRoutes(RouteCollection routes)
 {
            routes.EnableFriendlyUrls(new FriendlyUrlSettings()
            {
                AutoRedirectMode = RedirectMode.Permanent,
                ResolverCachingMode = ResolverCachingMode.Dynamic
            });
            routes.MapPageRoute("Sitemap", "sitemap.xml", "~/sitemap.aspx");
}
با این تنظیمات، سیستم مسیریابی ملزم به انتقال دائمی آدرس، به آدرس جدید خواهد شد. یعنی شما حتی اگر آدرس https://www.dntips.ir/sitemap.aspx را وارد نمایید مسیریاب سایت برای آدرس مورد نظر، وضعیت 301 Moved Permanently را مقدار دهی کرده و فقط آدرس https://www.dntips.ir/sitemap.xml به عنوان آدرس اصلی در نظر گرفته خواهد شد.
نظرات مطالب
آموزش (jQuery) جی کوئری 5#
سلام؛ من یه اسلاید شو ساده را از اموزشهای یه سایت انگلیسی زبان ساختم که مدتهاست دنبالش بودم
اما هنوز یه ایراد کوچولو داره و اونهم اینه که بعد از رسیدن به اخرین عکس برمیگرده به اول یعنی بصورت بک اسلاید میشه و اگر عکسها از سمت راست به چپ اسلاید میشوند وقتی به اخرین عکس میرسه تمام عکسها در کسری از ثانیه از چپ به راست برمیگردند. نمونه کد کوئری رو میزارم و ممنون میشم منو در این زمینه راهنمایی کنید که چطور کاری کنم با رسیدن به اخرین عکس به همون روش از سمت راست به چپ دوباره برگرده به عکس اول نه تمام عکسها رو از چپ به راست برگردونه ؟
اسکریپت فراخوانده شده :
  < script src = "http://code.jquery.com/jquery-latest.js" ></ script >
 کوئری نوشته شده : 
<script type = "text/javascript" >
$(document).ready(function () { 
   slideShow();
});
 
var n = 0;
function slideShow() {
   id = n % 5 + 1;
   leftpost = (1 - parseInt(id)) * 500 + "px";
   $("div.slider-item").animate({ left: leftpost }, 1500);
   n = n + 1;
   s = setTimeout("slideShow()", 3000);
}
 </ script >
فایل css :
 

<style type = "text/css" >
div#slider {
  width: 500px;
  height: 300px;
  margin: auto;
  overflow: hidden;
  border: 10px solid gray;
}
div#slider-mask {
  width: 500%;
  height: 100%;
}
div.slider-item {
  width: 20%;
  height: 100%;
  position: relative;
  float: left;
}
 </ style >
فایل html :
  < div id = "slider" > < div id = "slider-mask" > 
< div class = "slider-item" >< img src = "img1.jpg" alt = "1" /></ div > 
< div class = "slider-item" >< img src = "img2.jpg" alt = "2" /></ div > 
< div class = "slider-item" >< img src = "img3.jpg" alt = "3" /></ div >
 < div class = "slider-item" >< img src = "img4.jpg" alt = "4" /></ div > 
< div class = "slider-item" >< img src = "img5.jpg" alt = "5" /></ div >
</ div > </ div >
مطالب
مروری بر کتابخانه ReactJS - قسمت دوم - نصب و پیکربندی React‌JS برای Visual Studio Code

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

var ClickableImage = function (props) {
    return (
        <a href={props.href}>
            <img src={props.src} />
        </a>
    )
};
میان یک فایل جاوااسکریپت، از تگ‌های HTML استفاده شده‌است. چرا و چطور؟! 

React از دو روش برای ساخت تگ‌ها استفاده میکند. روش ساده‌تر همین مثالی است که در بالا آمده؛ یعنی از تگ‌های HTML را به صورت مستقیم استفاده می‌کند. روش دیگر، استفاده از زبان جاوااسکریپت به تنهایی است. مثلا تگ‌های <a> و <img>  بالا به صورت زیر نوشته میشوند:

var ClickableImage = function(props) {
    React.createElement(
        "a", 
        {href: props.href}, 
        React.createElement(
            "img",
            {src: props.src}
        )
    )
};

وقتی تصور کنیم که قرار است یک جدول یا یک فرم را ایجاد کنیم، ارزش روش ساده‌تر، مشخص میشود. در واقع تگ‌هایی که استفاده شده، واقعا تگ‌های HTML نیستند؛ چیزی هستند به نام JSX.  


JSX

JSX زبان یا روشی است که اجازه میدهد از تگ‌های مشابه با HTML در جاوااسکریپت استفاده کنیم. به دلیل تفاوت‌های مختصری که دارند، گفته شد که این تگ‌ها دقیقا HTML نیستند. برای مثال در تگ‌های HTML خاصیت‌های class و for را داریم؛ اما در تگ‌های JSX باید به ترتیب از className و htmlFor استفاده کنیم. مسئله بعدی این است که اساسا JSX همراه با React ارائه نشده و برای اینکه بتوانیم از JSX استفاده کنیم، نیاز به ابزاری اضافه داریم تا JSX را برای JavaScript و مرورگر ترجمه کند که فیسبوک، Babel را پیشنهاد میدهد. اگر از JSX بدون ابزار مترجم استفاده کنیم با پیام خطای زیر مواجه می‌شویم. 

  > Uncaught SyntaxError: Unexpected token

یعنی کاراکتر شروع (>) تگ‌ها را تشخیص نمیدهد.


نصب کتابخانه‌ها

این کتابخانه‌ها را می‌شود به مدل‌های مختلفی دریافت و پیکربندی کرد. بسته به نوع پروژه و محیط توسعه و پیکربندی‌های خاص هر پروژه، روش کار میتواند متفاوت باشد. هدف اصلی، مروری بر امکانات React است. پس ساده‌ترین روش نصب را برای ادامه کار انتخاب میکنیم. مانند هر کتابخانه‌ی دیگری میشود بطور یکجا React و Babel را از سایت‌های اصلی یا Github دانلود و به پروژه اضافه و استفاده کرد؛ مثل jQuery و Bootstrap. اما راه استاندارد و پیشنهاد شده، استفاده از ابزارهای مدیریت بسته‌ها مثل npm است. در قدم اول با فرض بر اینکه VSCode و npm بر روی سیستم نصب هستند، اول یک پوشه خالی را در VSCode به عنوان پروژه باز میکنیم و از منوی View -> Integrated Terminal  را انتخاب میکنیم. در ترمینال باز شده دستور نصب زیر را وارد میکنیم.

npm install react react-dom
با این کار پوشه node_modules به ریشه پروژه اضافه میشود که حاوی کتابخانه React است. پوشه node_modules مختص به React نیست. هر کتابخانه‌ای را که به این صورت نصب کنیم، به این پوشه اضافه میشود. مرحله بعد، نصب کتابخانه Babel جهت استفاده‌ی از JSX است. کتابخانه Babel یک مترجم بزرگ است که اجزای مختلفی دارد. ما به حداقل‌هایی از آن برای ترجمه تگ‌های JSX  احتیاج داریم. برای این کار همانند قبل، ترمینال را انتخاب میکنیم و دستور نصب زیر را اجرا میکنیم. با این دستور نصب، کتابخانه مختصر babel-standalone به پوشه node_modules اضافه میشود.
npm install babel-standalone

نحوه استفاده

فایل index.html را به ریشه پروژه اضافه کنید و کدهای زیر را درون تگ Body قرار دهید: 

<div id="reactTestContainer"></div>

<script src="node_modules/react/dist/react.min.js"></script>
<script src="node_modules/react-dom/dist/react-dom.min.js"></script>
<script src="node_modules/babel-standalone/babel.min.js"></script>
<script src="react-test.js" type="text/babel"></script>

برای کار با کتابخانه React به دو فایل react.js و react-dom.js نیاز داریم. اولی بخش اصلی کتابخانه و دومی برای ساخت تگ‌ها و تبادل با بخش HTML DOM استفاده میشود؛ مثلا اضافه کردن تگ‌های ساخته شده به HTML. ذکر ویژگی "type="text/babel برای فایل‌هایی که در آنها از تگ‌های JSX استفاده شده ضروری است؛ در غیر اینصورت Babel  تشخیص نمیدهد که کار ترجمه را برای چه فایلهایی باید انجام دهد. در نهایت قطعه کد زیر را در فایل react-test.js وارد کنید. 

var ClickableImage = function (props) {
    return (
        <a href={props.href}>
            <img src={props.src} />
        </a>
    )
};

ReactDOM.render(
    <ClickableImage href="http://google.com" src="google.jpg"/>, 
    document.getElementById("reactTestContainer")
)

با اجرا کردن پروژه، تصویری قابل کلیک به مقصد گوگل، در تگ <div>، با ویژگی "id=”reactTestContainer ایجاد خواهد شد.

تا به این قسمت متوجه شدیم که کتابخانه React چیست و چطور میشود از آن استفاده کرد. در قسمت بعد نگاهی دقیق‌تر به کامپوننت‌های React خواهیم داشت.

مطالب
Vue.js - بحث Computed Properties و خروجی بلادرنگ - قسمت سوم
با استفاده از Computed Properties ها می‌توانید برای هر خاصیت، یک شرط بنویسید و آنرا مقداردهی کنید. در این بحث بسیار مهم نیز قادر خواهید بود تا به صورت بلادرنگ (Real Time) خروجی بگیرید. در واقع به محض ارسال اطلاعات، خروجی مورد نظر برای شما نمایش داده می‌شود.
ابتدا لازم است تا یک ویو را ایجاد کنید. یک new vue جدید ساخته و مشخصه‌های لازم را وارد کنید؛ مطابق کد زیر
    <html> <body>

    <div id="dotnet"> 
       <h2>New Sample: {{ a }}</h2> 
       <input type="text" v-model="a"> 
    </div> 
  
       <script src="https://unpkg.com/vue@2.2.6">
       </script>

       <script type="text/javascript">
        new Vue({ 
        el: '#dotnet', 
        data:{ 
            a:'' 
        }, 
        computed: { 
            a:{ 
                get: function () { 
                    return this.a + ''; 
                } 
            } 
        } 
    });
        </script>

        </body>
</html>
در کد بالا ویوی جدیدی ساخته شده و مقدار data نیز مشخص شده‌است. مقدار data برابر a می‌باشد.
data:{ 
            a:'' 
        },
دقت نمائید هدف این است وقتی مقداری درون یک input وارد می‌شود، بلافاصله نمایش داده شود که این کار با استفاده از خاصیت v-model به صورت بلادرنگ امکان‌پذیر است.
در کد زیر مقدار a درون data باید به v-model نسبت داده شود تا درون input اطلاعات نمایش داده شوند.
<input type="text" v-model="a">
حال، یک property به نام computed  ایجاد کرده و مقدار a را توسط یک تابع برگشت می‌دهیم.
  computed: { 
            a:{ 
                get: function () { 
                    return this.a + ''; 
                } 
            } 
        }
دقت کنید function بالا به دلخواه نوشته شده‌است و شما قادرید هرکدی را که لازم است، جای آن بنویسید. اما بدنه کلی ساختار یک computed  باید به همین شکل حفظ شود.
پس از اجرای کد درون مرورگر هر نوع مقداری که درون input وارد شود، توسط خاصیت v-model بلافاصله نمایش داده می‌شود.