خواندن اطلاعات از سرور و نمایش آن توسط Angular در ASP.NET MVC
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: سه دقیقه

می خواهیم یک مثال ساده از دریافت اطلاعات از سرور و نمایش آن در یک View را توسط AngularJS، با هم بررسی کنیم.
همانطور که می‌دانید برای نمایش تعدادی از اشیاء در انگولار می‌توان به این صورت نیز عمل کرد:
<div ng-init="products=[
     {id:1,name:'product1',price:25000,description:'description of product'},
     {id:2,name:'product2',price:5000,description:'description of product'},
     {id:3,name:'product3',price:5000,description:'description of product'},
     {id:4,name:'product4',price:2000,description:'description of product'},
     {id:5,name:'product5',price:255000,description:'description of product'}
     ]">
    <div>
        <div>
            <table>
                <tr>
                    <th>Id</th>
                    <th>Product Name</th>
                    <th>Price</th>
                    <th>Description</th>
                </tr>
                <tr ng-repeat="product in products">
                    <td>{{product.id}}</td>
                    <td>{{product.name}}</td>
                    <td>{{product.price}}</td>
                    <td>{{product.description}}</td>
                </tr>
            </table>
        </div>
    </div>
</div>
در کد فوق توسط ویژگی ng-init می‌توانیم داده هایمان را Initialize کنیم و در نهایت توسط ویژگی ng-repeat می‌توانیم داده هایمان را در صفحه نمایش دهیم. این ویژگی دقیقاً مانند یک حلقه foreach عمل میکند؛ مثلا معادل آن در Razor سمت سرور، به این صورت است:
@foreach (var product in Model.products)
{
    <td>product.id</td>
    <td>product.name</td>
    <td>product.price</td>
    <td>product.description</td>
}
خوب؛ حالا میخواهیم این اطلاعات را از سمت سرور بخوانیم و به صورت فوق نمایش دهیم. ابتدا مدل مان را به این صورت تعریف می‌کنیم :
namespace AngularAndMvc.Models
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public float Price { get; set; }
        public string Description { get; set; }
    }
}
سپس در داخل کنترلر زیر اطلاعات را به صورت in memory data تعریف می‌کنیم (جهت سهولت دموی کار) و به view مورد نظر پاس می‌دهیم. البته شما می‌توانید این اطلاعات را از دیتابیس بخوانید؛ روال کار فرقی نمی‌کند:
namespace AngularAndMvc.Controllers
{
    public class ProductController : Controller
    {        
        public ActionResult Index()
        {
            return View("Index", "", GetSerializedProduct());
        }

        public string GetSerializedProduct()
        {
            var products = new[] 
            { 
                new Product{Id=1,Name="product1",Price=4500,Description="description of this product"},
                new Product{Id=2,Name="product2",Price=500,Description="description of this product"},
                new Product{Id=3,Name="product3",Price=400,Description="description of this product"},
                new Product{Id=4,Name="product4",Price=5500,Description="description of this product"},
                new Product{Id=5,Name="product5",Price=66500,Description="description of this product"}
            };
            var settings = new JsonSerializerSettings { ContractResolver=new CamelCasePropertyNamesContractResolver()};
            return JsonConvert.SerializeObject(products,Formatting.None,settings);
        }
   }
}
همانطور که در کد بالا مشخص است، اطلاعات را به صورت JSON به View مان پاس داده ایم و برای اینکه ابتدای نام مقادیر بازگشتی به صورت حروف بزرگ نباشند (به صورت خودکار تبدیل به camel case شوند) پارامتر settings را برای متد SerializeObject تعیین کرده‌ایم:
var settings = new JsonSerializerSettings { ContractResolver=new CamelCasePropertyNamesContractResolver()};
return JsonConvert.SerializeObject(products,Formatting.None,settings);
view را نیز به این صورت تغییر می‌دهیم :
@model string
<div ng-init="products = @Model">
    <div>
        <div>
            <table>
                <tr>
                    <th>Id</th>
                    <th>Product Name</th>
                    <th>Price</th>
                    <th>Description</th>
                </tr>
                <tr ng-repeat="product in products">
                    <td>{{product.id}}</td>
                    <td>{{product.name}}</td>
                    <td>{{product.price}}</td>
                    <td>{{product.description}}</td>
                </tr>
            </table>
        </div>
    </div>
</div>
تنها تغییری که در کد فوق اعمال شده است، به جای اینکه ویژگی ng-init را به صورت inline مقداردهی کنیم آن را از کنترلر دریافت کرده ایم.
در خروجی هم اطلاعات به این صورت نمایش داده می‌شوند :

سورس مثال فوق را هم از اینجا  می توانید دریافت کنید.

  • #
    ‫۱۰ سال و ۶ ماه قبل، جمعه ۱۵ فروردین ۱۳۹۳، ساعت ۱۵:۴۵
    با تشکر 
    من از این روش در یک view استفاده کردم (در اینجا هدف نمایش لیست کاربران بود) ولی مشکل من این هست که وقتی این view برای کاربر نمایش داده میشه چون انگولار اون رو کش میکنه با افزودن کاربر جدید این لیست تا درخواست مجدد از سرور بروز نمیشه.
    میخواستم بدونم آیا با واکشی اطلاعات توسط http$ مشکلم حل میشه؟
    یا میشه یک view در انگولار کش نشود و به هر با route به اون view مورد نظر از سرور فراخوانی بشه
    • #
      ‫۱۰ سال و ۶ ماه قبل، جمعه ۱۵ فروردین ۱۳۹۳، ساعت ۱۶:۲۲
      البته می‌تونید کش رو سمت سرور با اعمال outputcache بر روی اکشن خودتون غیر فعال کنید:
      [OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
      public ActionResult Index()
      {
            return View("Index", "", GetSerializedProduct());
      }
    • #
      ‫۱۰ سال و ۶ ماه قبل، شنبه ۱۶ فروردین ۱۳۹۳، ساعت ۱۵:۲۳
      در روش بالا اگر چه اطلاعات از سرور دریافت میشود اما حالتی استاتیک دارد چون لیست محصولات در زمان رندر شدن صفحه تولید و در ng-init قرار می‌گیرد . و در نتیجه برای بروزکردن حتما باید صفحه مجددا درخواست بشود (رفرش). این روش برای لیست هایی که تغییراتی ندارند یا به ندرت تغییر می‌کنند مناسب است.
      و بله یک راه برای حل این مشکل استفاده از سرویس http می‌تواند باشد .
  • #
    ‫۷ سال و ۱۰ ماه قبل، شنبه ۲۹ آبان ۱۳۹۵، ساعت ۰۱:۳۰
    ممنون از مطلب مفیدی که منتشر کردید.
    برای نمایش دادن لیستی از شهرها در یک DropDown بهتر است  از بانک اطلاعاتی خواند شود یا شهرها را  با استفاده از JavaScript در Client تعریف کنیم؟
    • #
      ‫۷ سال و ۱۰ ماه قبل، شنبه ۲۹ آبان ۱۳۹۵، ساعت ۱۲:۳۶
      اگر هدف ذخیره value آپشن‌های لیست باشد (در حالتی که ای‌دی هر شهر را بخواهید ذخیره کنید) بهتر است این اطلاعات از سرور دریافت شوند؛ در اینحالت مطمئن خواهیم شد که همان مقادیر درون دیتابیس برای value در نظر گرفته خواهند شد؛ البته در اینحالت هم می‌شود id را hardcode کرد؛ اما در شرایطی که نوع آی‌دی به صورت Guid باشد مدیریت آن مقداری سخت خواهد شد:
      <select id="cities">
          <option value="246c899b-f6e8-e511-b696-001f29ea72a6">Tehran</option>
          <option value="256c899b-f6e8-e511-b696-001f29ea72a6">Kurdistan</option>
      </select>

      اما اگر هدف ذخیره متن هر آیتم است و از آنجائیکه مقادیر ثابت هستند می‌توانید به اینصورت عمل کنید:
       
      $scope.cities = [
      "Tehran",
      "Sanandaj"
      ];
      
      <select>
      <option ng-repeat="city in cities">{{city}}</option>
      </select>