فعال سازی عملیات CRUD در Kendo UI Grid
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: هشت دقیقه

پیشنیاز بحث
- «فرمت کردن اطلاعات نمایش داده شده به کمک Kendo UI Grid»

Kendo UI Grid دارای امکانات ثبت، ویرایش و حذف توکاری است که در ادامه نحوه‌ی فعال سازی آن‌‌ها را بررسی خواهیم کرد. مثالی که در ادامه بررسی خواهد شد، در تکمیل مطلب «فرمت کردن اطلاعات نمایش داده شده به کمک Kendo UI Grid» است.



تنظیمات Data Source سمت کاربر

برای فعال سازی صفحه بندی سمت سرور، با قسمت read منبع داده Kendo UI پیشتر آشنا شده بودیم. جهت فعال سازی قسمت‌های ثبت اطلاعات جدید (create)، به روز رسانی رکوردهای موجود (update) و حذف ردیفی مشخص (destroy) نیاز است تعاریف قسمت‌های متناظر را که هر کدام به آدرس مشخصی در سمت سرور اشاره می‌کنند، اضافه کنیم:
            var productsDataSource = new kendo.data.DataSource({
                transport: {
                    read: {
                        url: "api/products",
                        dataType: "json",
                        contentType: 'application/json; charset=utf-8',
                        type: 'GET'
                    },
                    create: {
                        url: "api/products",
                        contentType: 'application/json; charset=utf-8',
                        type: "POST"
                    },
                    update: {
                        url: function (product) {
                            return "api/products/" + product.Id;
                        },
                        contentType: 'application/json; charset=utf-8',
                        type: "PUT"
                    },
                    destroy: {
                        url: function (product) {
                            return "api/products/" + product.Id;
                        },
                        contentType: 'application/json; charset=utf-8',
                        type: "DELETE"
                    },
                    //...
                },
                schema: {
                    //...
                    model: {
                        id: "Id", // define the model of the data source. Required for validation and property types.
                        fields: {
                            "Id": { type: "number", editable: false }, //تعیین نوع فیلد برای جستجوی پویا مهم است
                            "Name": { type: "string", validation: { required: true } },
                            "IsAvailable": { type: "boolean" },
                            "Price": { type: "number", validation: { required: true, min: 1 } },
                            "AddDate": { type: "date", validation: { required: true } }
                        }
                    }
                },
                batch: false, // enable batch editing - changes will be saved when the user clicks the "Save changes" button
                //...
            });
- همانطور که ملاحظه می‌کنید، حالت‌های update و destroy بر اساس Id ردیف انتخابی کار می‌کنند. این Id را باید در قسمت model مربوط به اسکیمای تعریف شده، دقیقا مشخص کرد. عدم تعریف فیلد id، سبب خواهد شد تا عملیات update نیز در حالت create تفسیر شود.
- به علاوه در اینجا به ازای هر فیلد، مباحث اعتبارسنجی نیز اضافه شده‌اند؛ برای مثال فیلدهای اجباری با required: true مشخص گردیده‌اند.
- اگر فیلدی نباید ویرایش شود (مانند فیلد Id)، خاصیت editable آن‌را false کنید.
- در data source امکان تعریف خاصیتی به نام batch نیز وجود دارد. حالت پیش فرض آن false است. به این معنا که در حالت ویرایش، تغییرات هر ردیفی، یک درخواست مجزا را به سمت سرور سبب خواهد شد. اگر آن‌را true کنید، تغییرات تمام ردیف‌ها در طی یک درخواست به سمت سرور ارسال می‌شوند. در این حالت باید به خاطر داشت که پارامترهای سمت سرور، از حالت یک شیء مشخص باید به لیستی از آن‌ها تغییر یابند.


مدیریت سمت سرور ثبت، ویرایش و حذف اطلاعات

در حالت ثبت، متد Post، توسط آدرس مشخص شده در قسمت create منبع داده گرید، فراخوانی می‌گردد:
namespace KendoUI06.Controllers
{
    public class ProductsController : ApiController
    {
        public HttpResponseMessage Post(Product product)
        {
            if (!ModelState.IsValid)
                return Request.CreateResponse(HttpStatusCode.BadRequest);

            var id = 1;
            var lastItem = ProductDataSource.LatestProducts.LastOrDefault();
            if (lastItem != null)
            {
                id = lastItem.Id + 1;
            }
            product.Id = id;
            ProductDataSource.LatestProducts.Add(product);

            var response = Request.CreateResponse(HttpStatusCode.Created, product);
            response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = product.Id }));
            // گرید آی دی جدید را به این صورت دریافت می‌کند
            response.Content = new ObjectContent<DataSourceResult>(
                new DataSourceResult { Data = new[] { product } }, new JsonMediaTypeFormatter());
            return response;
        }
    }
}
نکته‌ی مهمی که در اینجا باید به آن دقت داشت، نحوه‌ی بازگشت Id رکورد جدید ثبت شده‌است. در این مثال، قسمت schema منبع داده سمت کاربر به نحو ذیل تعریف شده‌است:
            var productsDataSource = new kendo.data.DataSource({
                //...
                schema: {
                    data: "Data",
                    total: "Total",
                }
                //...
            });
از این جهت که خروجی متد Get بازگرداننده‌ی اطلاعات صفحه بندی شده، از نوع DataSourceResult است و این نوع، دارای خواصی مانند Data، Total و Aggergate است:
namespace KendoUI06.Controllers
{
    public class ProductsController : ApiController
    {
        public DataSourceResult Get(HttpRequestMessage requestMessage)
        {
            var request = JsonConvert.DeserializeObject<DataSourceRequest>(
                requestMessage.RequestUri.ParseQueryString().GetKey(0)
            );

            var list = ProductDataSource.LatestProducts;
            return list.AsQueryable()
                       .ToDataSourceResult(request.Take, request.Skip, request.Sort, request.Filter);
        }
    }
}
بنابراین در متد Post نیز باید بر این اساس، response.Content را از نوع لیستی از DataSourceResult تعریف کرد تا Kendo UI Grid بداند که Id رکورد جدید را باید از فیلد Data، همانند تنظیمات schema منبع داده خود، دریافت کند.
response.Content = new ObjectContent<DataSourceResult>(
                              new DataSourceResult { Data = new[] { product } }, new JsonMediaTypeFormatter());
اگر این تنظیم صورت نگیرد، Id رکورد جدید را در گرید، مساوی صفر مشاهده خواهید کرد و عملا بدون استفاده خواهد شد؛ زیرا قابلیت ویرایش و حذف خود را از دست می‌دهد.

متدهای حذف و به روز رسانی سمت سرور نیز چنین امضایی را خواهند داشت:
namespace KendoUI06.Controllers
{
    public class ProductsController : ApiController
    {
        public HttpResponseMessage Delete(int id)
        {
            var item = ProductDataSource.LatestProducts.FirstOrDefault(x => x.Id == id);
            if (item == null)
                return Request.CreateResponse(HttpStatusCode.NotFound);

            ProductDataSource.LatestProducts.Remove(item);

            return Request.CreateResponse(HttpStatusCode.OK, item);
        }

        [HttpPut] // Add it to fix this error: The requested resource does not support http method 'PUT'
        public HttpResponseMessage Update(int id, Product product)
        {
            var item = ProductDataSource.LatestProducts
                                        .Select(
                                            (prod, index) =>
                                                new
                                                {
                                                    Item = prod,
                                                    Index = index
                                                })
                                        .FirstOrDefault(x => x.Item.Id == id);
            if (item == null)
                return Request.CreateResponse(HttpStatusCode.NotFound);


            if (!ModelState.IsValid || id != product.Id)
                return Request.CreateResponse(HttpStatusCode.BadRequest);

            ProductDataSource.LatestProducts[item.Index] = product;
            return Request.CreateResponse(HttpStatusCode.OK);
        }
    }
}
حالت Update از HTTP Verb خاصی به نام Put استفاده می‌کند و ممکن است در این بین خطای The requested resource does not support http method 'PUT' را دریافت کنید. برای رفع آن ابتدا بررسی کنید که آیا Web.config برنامه دارای تعاریف ExtensionlessUrlHandler هست یا خیر. همچنین مزین کردن این متد با ویژگی HttpPut، مشکل را برطرف می‌کند.


تنظیمات Kendo UI Grid جهت فعال سازی CRUD

در ادامه کلیه تغییرات مورد نیاز جهت فعال سازی CRUD را در Kendo UI، به همراه مباحث بومی سازی عبارات متناظر با دکمه‌ها و صفحات خودکار مرتبط، مشاهده می‌کنید:
            $("#report-grid").kendoGrid({
                //....
                editable: {
                    confirmation: "آیا مایل به حذف ردیف انتخابی هستید؟",
                    destroy: true, // whether or not to delete item when button is clicked
                    mode: "popup", // options are "incell", "inline", and "popup"
                    //template: kendo.template($("#popupEditorTemplate").html()), // template to use for pop-up editing
                    update: true, // switch item to edit mode when clicked?
                    window: {
                        title: "مشخصات محصول"   // Localization for Edit in the popup window
                    }
                },
                columns: [
                //....
                    {
                        command: [
                            { name: "edit", text: "ویرایش" },
                            { name: "destroy", text: "حذف" }
                        ],
                        title: "&nbsp;", width: "160px"
                    }
                ],
                toolbar: [
                    { name: "create", text: "افزودن ردیف جدید" },
                    { name: "save", text: "ذخیره‌ی تمامی تغییرات" },
                    { name: "cancel", text: "لغو کلیه‌ی تغییرات" },
                    { template: kendo.template($("#toolbarTemplate").html()) }
                ],
                messages: {
                    editable: {
                        cancelDelete: "لغو",
                        confirmation: "آیا مایل به حذف این رکورد هستید؟",
                        confirmDelete: "حذف"
                    },
                    commands: {
                        create: "افزودن ردیف جدید",
                        cancel: "لغو کلیه‌ی تغییرات",
                        save: "ذخیره‌ی تمامی تغییرات",
                        destroy: "حذف",
                        edit: "ویرایش",
                        update: "ثبت",
                        canceledit: "لغو"
                    }
                }
            });
- ساده‌ترین حالت CRUD در Kendo UI با مقدار دهی خاصیت editable آن به true آغاز می‌شود. در این حالت، ویرایش درون سلولی یا incell فعال خواهد شد که مباحث batching ابتدای بحث، فقط در این حالت کار می‌کند. زمانیکه incell editing فعال است، کاربر می‌تواند تمام ردیف‌ها را ویرایش کرده و در آخر کار بر روی دکمه‌ی «ذخیره‌ی تمامی تغییرات» موجود در نوار ابزار، کلیک کند. در سایر حالات، هر بار تنها یک ردیف را می‌توان ویرایش کرد.
- برای فعال سازی تولید صفحات خودکار ویرایش و افزودن ردیف‌ها، نیاز است خاصیت editable را به نحوی که ملاحظه می‌کنید، مقدار دهی کرد. خاصیت mode آن سه حالت incell (پیش فرض)، inline و popup را پشتیبانی می‌کند.
- اگر حالت‌های inline و یا popup را فعال کردید، در انتهای ستون‌های تعریف شده، نیاز است ستون ویژه‌ای به نام command را مطابق تعاریف فوق، تعریف کنید. در این حالت دو دکمه‌ی ویرایش و ثبت، فعال می‌شوند و اطلاعات خود را از تنظیمات data source گرید دریافت می‌کنند. دکمه‌ی ویرایش در حالت incell کاربردی ندارد (چون در این حالت کاربر با کلیک درون یک سلول می‌تواند آن‌را مانند برنامه‌ی اکسل ویرایش کند). اما دکمه‌ی حذف در هر سه حالت قابل استفاده است.
- به نوار ابزار گرید، سه دکمه‌ی افزودن ردیف‌های جدید، ذخیره‌ی تمامی تغییرات و لغو تغییرات صورت گرفته، اضافه شده‌اند. این دکمه‌ها استاندارد بوده و در اینجا نحوه‌ی بومی سازی پیام‌های مرتبط را نیز مشاهده می‌کنید. همانطور که عنوان شد، دکمه‌های «تمامی تغییرات» در حالت فعال سازی batching در منبع داده و استفاده از incell editing معنا پیدا می‌کند. در سایر حالات این دو دکمه کاربردی ندارند. اما دکمه‌ی افزودن ردیف‌های جدید در هر سه حالت کاربرد دارد و یکسان است.


کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید
KendoUI06.zip
  • #
    ‫۹ سال و ۱۰ ماه قبل، چهارشنبه ۲۱ آبان ۱۳۹۳، ساعت ۱۳:۱۵
    یک نکته‌ی تکمیلی
    در مثال فوق از ASP.NET Web API استفاده شده‌است. اگر علاقمند به استفاده از WCF و یا حتی فایل‌های asmx قدیمی هم باشید، اینکار میسر است. مثال‌هایی را در این زمینه، در اینجا می‌توانید مشاهده کنید.
  • #
    ‫۹ سال و ۸ ماه قبل، یکشنبه ۱۹ بهمن ۱۳۹۳، ساعت ۱۱:۳۷
    در بحث Grid در پلتفرم  KendoUI آیا راهی هست که بتونیم بوسیله کوکی براحتی آخرین وضعیت گرید را ذخیره  کنیم تا در مراجعه بعدی بصورت اتوماتیک وضعیت قبلی را لود کنه؟ متشکرم
  • #
    ‫۹ سال و ۸ ماه قبل، یکشنبه ۱۹ بهمن ۱۳۹۳، ساعت ۱۴:۰۳
    سلام، 
    هنگام تغییر خطای زیر را دریافت می‌کنم، هر چند تغییرات ذخیره می‌شوند و فقط این خطا بی‌جهت داده می‌شود. از این روش‌ها ( +  و  + ) برای دریافت اطلاعات استفاده کردم. به نظر شما مشکل کجاست و یا چطور می‌شه دیباگ کرد؟

    • #
      ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۴:۴۲
      مثال فوق را (KendoUI06) اگر برای ASP.NET MVC بازنویسی کنیم به کدهای ذیل خواهیم رسید:
      using System.Linq;
      using System.Net;
      using System.Net.Http;
      using System.Web.Mvc;
      using Kendo.DynamicLinq;
      using KendoUI06Mvc.Models;
      using Newtonsoft.Json;
      
      namespace KendoUI06Mvc.Controllers
      {
          public class HomeController : Controller
          {
              public ActionResult Index()
              {
                  return View(); // shows the page.
              }
      
              [HttpDelete]
              public ActionResult DeleteProduct(int id)
              {
                  var item = ProductDataSource.LatestProducts.FirstOrDefault(x => x.Id == id);
                  if (item == null)
                      return new HttpNotFoundResult();
      
                  ProductDataSource.LatestProducts.Remove(item);
      
                  return Json(item);
              }
      
              [HttpGet]
              public ActionResult GetProducts()
              {
                  var request = JsonConvert.DeserializeObject<DataSourceRequest>(
                     this.Request.Url.ParseQueryString().GetKey(0)
                  );
      
                  var list = ProductDataSource.LatestProducts;
                  return Json(list.AsQueryable()
                             .ToDataSourceResult(request.Take, request.Skip, request.Sort, request.Filter),
                             JsonRequestBehavior.AllowGet);
              }
      
              [HttpPost]
              public ActionResult PostProduct(Product product)
              {
                  if (!ModelState.IsValid)
                      return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
      
                  var id = 1;
                  var lastItem = ProductDataSource.LatestProducts.LastOrDefault();
                  if (lastItem != null)
                  {
                      id = lastItem.Id + 1;
                  }
                  product.Id = id;
                  ProductDataSource.LatestProducts.Add(product);
      
                  // گرید آی دی جدید را به این صورت دریافت می‌کند
                  return Json(new DataSourceResult { Data = new[] { product } });
              }
      
              [HttpPut] // Add it to fix this error: The requested resource does not support http method 'PUT'
              public ActionResult UpdateProduct(int id, Product product)
              {
                  var item = ProductDataSource.LatestProducts
                                              .Select(
                                                  (prod, index) =>
                                                      new
                                                      {
                                                          Item = prod,
                                                          Index = index
                                                      })
                                              .FirstOrDefault(x => x.Item.Id == id);
                  if (item == null)
                      return new HttpNotFoundResult();
      
      
                  if (!ModelState.IsValid || id != product.Id)
                      return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
      
                  ProductDataSource.LatestProducts[item.Index] = product;
      
                  //Return HttpStatusCode.OK
                  return new HttpStatusCodeResult(HttpStatusCode.OK);
              }
          }
      }
      در این حالت View برنامه فقط جهت ذکر آدرس‌های جدید باید اصلاح شود و نیاز به تغییر دیگری ندارد:
              var productsDataSource = new kendo.data.DataSource({
                  transport: {
                      read: {
                          url: "@Url.Action("GetProducts","Home")",
                          dataType: "json",
                          contentType: 'application/json; charset=utf-8',
                          type: 'GET'
                      },
                      create: {
                          url: "@Url.Action("PostProduct","Home")",
                          contentType: 'application/json; charset=utf-8',
                          type: "POST"
                      },
                      update: {
                          url: function (product) {
                              return "@Url.Action("UpdateProduct","Home")/" + product.Id;
                              },
                              contentType: 'application/json; charset=utf-8',
                              type: "PUT"
                          },
                          destroy: {
                              url: function (product) {
                                  return "@Url.Action("DeleteProduct","Home")/" + product.Id;
                              },
                              contentType: 'application/json; charset=utf-8',
                              type: "DELETE"
                          },
                          parameterMap: function (options) {
                              return kendo.stringify(options);
                          }
                      },
    • #
      ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۸:۱۱
      برای کسانی که از روش GitHub لینک داده شده استفاده کردند و مشکل بنده رو هنگام Update اطلاعات دارند: در ActionResult مربوط به Update گریدویو Kendu UI هنگام بازگشت مقدار Json به صورت null باید از عبارت رشته‌ای خالی شبیه زیر استفاده کنیم:
               [HttpPost]
              public ActionResult Update(IEnumerable<Product> products)
              {
                      //  ....
                      //Return emtpy result
                      return Json("");
              }
      موفق باشید.
  • #
    ‫۹ سال و ۶ ماه قبل، جمعه ۲۲ اسفند ۱۳۹۳، ساعت ۱۴:۳۶
    سلام؛  در مثال فوق وفتی میخوام یک رکور جدید درج کنم خطای Internal Server Error  میده!
    راستی این تکه کد منظور از مقدار name چیه؟
              toolbar: [
                       { name: "create", text: "افزودن ردیف جدید" },
                       { name: "save", text: "ذخیره‌ی تمامی تغییرات" },
                       { name: "cancel", text: "لغو کلیه‌ی تغییرات" },
                       { template: kendo.template($("#toolbarTemplate").html()) }
                ],
    • #
      ‫۹ سال و ۶ ماه قبل، جمعه ۲۲ اسفند ۱۳۹۳، ساعت ۱۴:۵۱
      - جزئیات خطای عمومی Internal Server Error را در برگه‌ی response فایرباگ می‌توانید مشاهده کنید. اطلاعات بیشتر
      - همچنین ELMAH را هم می‌توانید نصب کنید تا خطاها را بهتر بتوانید بررسی کنید.
      - کدهای مثال جاری را بازنویسی شده جهت ASP.NET MVC و بدون استفاده از Web API در اینجا می‌توانید مشاهده کنید. با این View و این Controller. کدهای سمت کلاینت و سمت سرور خودتان را با این دو فایل انطباق دهید.
      - name، نام یک سری command و دستور از پیش تعریف شده‌ی Kendo UI Grid است.
      • #
        ‫۹ سال و ۶ ماه قبل، جمعه ۲۲ اسفند ۱۳۹۳، ساعت ۱۷:۰۵
        همه چیز را چک کردم ولی بازم هم خطا میده!
        این هم جزییات response
        <h2> <i>Invalid JSON primitive: Id.</i> </h2></span>
        [ArgumentException: Invalid JSON primitive: Id.]
        System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializePrimitiveObject() +585

        من وقتی این صفحه داره Get میشه با استفاده از تکه کد زیر خروجی بر میگردونم. مشکل نداره؟
        string json = new JavaScriptSerializer().Serialize(list);
        return json;
        یعنی خروجی string بر میگردونم. مشکل داره؟
        • #
          ‫۹ سال و ۶ ماه قبل، جمعه ۲۲ اسفند ۱۳۹۳، ساعت ۱۷:۲۴
          - بله. مشکل دارد. خروجی دریافتی این گرید باید با فرمت DataSourceResult به صورت JSON ارسال شود (به صورت JSON ارسال شدن، شامل فرمت اطلاعات و همچنین تنظیم Content-Type آن است). جزئیات این فرمت و علت وجودی آن در مطلب «صفحه بندی، مرتب سازی و جستجوی پویای اطلاعات به کمک Kendo UI Grid» بررسی شده‌اند. به همین جهت در این مثال‌ها از متد ToDataSourceResult کمک گرفته شده‌است (هم در مثال وب API و هم در مثال MVC آن)
          - زمانیکه که خطای Invalid JSON primitive را در سمت سرور دریافت می‌کنید، یعنی سمت کلاینت، اطلاعات را با فرمت نادرستی به سمت سرور ارسال می‌کند و این فرمت JSON نیست. یعنی در قسمت DataSource اطلاعات اضافی و یا نادرستی وجود دارند که با View ذکر شده هماهنگ نیستند.

          همانطور که عنوان شد، قسمت‌های سمت سرور و سمت کلاینت را با مثال ارسالی هماهنگ کنید و انطباق دهید. اگر وب API است این مثال و اگر MVC است، این مثال.
  • #
    ‫۹ سال و ۶ ماه قبل، سه‌شنبه ۴ فروردین ۱۳۹۴، ساعت ۰۵:۰۶
    سلام؛ من میخوام در حین آپدیت یکی از رکورد هام یکی از فیلدهای من از نوع text area باشه تا کاربر بتونه متن بیشتری را وارد نماید. منظورم در حین popup هستش.
    • #
      ‫۹ سال و ۶ ماه قبل، سه‌شنبه ۴ فروردین ۱۳۹۴، ساعت ۰۶:۲۰
      $("#grid").kendoGrid({
      // ...
          columns:
          [
              {
                  field: "Your Field",
                  title: "Your Field Name",
                  width: "20%",
                  editor: function (container, options) {
                      $('<textarea cols="20" rows="4" data-bind="value: ' + options.field + '"></textarea>').appendTo(container);
                  }
              },
              // ...   
         ]
      // ...
      });
  • #
    ‫۹ سال و ۵ ماه قبل، یکشنبه ۶ اردیبهشت ۱۳۹۴، ساعت ۱۸:۴۸
    با سلام؛ در Grid  Kendoui چطور میشه یه ستون دیگه اضافه کرد که مثلا حاصل جمع دو ستون ( A+B ) را در این ستون جدید قرار بده؟
    • #
      ‫۹ سال و ۵ ماه قبل، یکشنبه ۶ اردیبهشت ۱۳۹۴، ساعت ۱۹:۱۶
      نکات مطلب «فرمت کردن اطلاعات نمایش داده شده به کمک Kendo UI Grid» را در مورد کار با قالب‌ها مطالعه کنید.
      روش اول:
      columns: [
                      { field: "units", title: "Units" },
                      { field: "price", title: "Price" },
                      { field: null, title: "Extended Price", template: '#= units * price #' }
                  ]
      روش دوم؛ یک ستون قالب دار با این فرمت اضافه می‌کنید: 
      #=calculateField(data)#
      که متد آن برای نمونه به این ترتیب محاسبه شود:
      //Passed data contains current row model
      function calculateField(data) {
        return data.f1 + " " + data.f2;
      }
  • #
    ‫۹ سال و ۵ ماه قبل، چهارشنبه ۹ اردیبهشت ۱۳۹۴، ساعت ۱۹:۴۵
    با سلام
    با توجه به مباحثی که در این درس بیان شده نمونه مثال شما با mvc بررسی شد ولی هنگام اجرا در زمان update هیچگونه اکشنی انجام نمیشه دیباک میکنم خطای زیر نشون داده میشه.

    • #
      ‫۹ سال و ۵ ماه قبل، چهارشنبه ۹ اردیبهشت ۱۳۹۴، ساعت ۱۹:۵۳
      کدهای « اصلی » مثال جاری را بازنویسی شده جهت ASP.NET MVC و بدون استفاده از Web API در اینجا می‌توانید مشاهده کنید. با این View و این Controller. کدهای سمت کلاینت و سمت سرور خودتان را با این دو فایل انطباق دهید. 
  • #
    ‫۹ سال و ۵ ماه قبل، چهارشنبه ۹ اردیبهشت ۱۳۹۴، ساعت ۲۱:۳۷
    با سلام
    اقای نصیری من دقیقا مثال شما رو دانلود کردم و اجرا کردم تو کنترل رو تابع UpdateProduct  بریک پوینت میزارم ولی اصلا وارد برنامه نمیشه.ویرایش انجام میشه تغییرات ثبت میشه ولی وارد کنترل نمیشه
    • #
      ‫۹ سال و ۵ ماه قبل، چهارشنبه ۹ اردیبهشت ۱۳۹۴، ساعت ۲۱:۵۸
      مثال « اصلی » بدون تغییر و با تمام فایل‌های آن به این صورت اجرا می‌شود:

      اگر در مثال « شما »، به نکته‌ی HttpPut و تنظیمات Web.Config ذکر شده‌ی در مطلب دقت نکرده باشید، قسمت HttpPut اجرا نخواهد شد.
      اطلاعات بیشتر
  • #
    ‫۹ سال و ۵ ماه قبل، سه‌شنبه ۱۵ اردیبهشت ۱۳۹۴، ساعت ۲۰:۵۴
    برای اینکه خطاهای ثبت شده در ModelState را  هنگام ثبت و ویرایش نمایش دهیم  باید  به صورت زیر عمل کنیم   
    return Json(resultData.AsQueryable().ToDataSourceResult(dataSourceRequest, ModelState));
    ولی این متد در فضای نام using Kendo.Mvc.Extensions قرار دارد .
    لازم است تا هم فیلترینگ سمت سرور و در لایه سرویس انجام شود و هم اینکه بتوان خطاهای ModelState نشان داده شود . به چه صورت باید عمل کرد؟
    با تشکر
    • #
      ‫۹ سال و ۵ ماه قبل، پنجشنبه ۱۷ اردیبهشت ۱۳۹۴، ساعت ۱۷:۲۰
      - «Handling Server-Side Validation Errors In Your Kendo UI Grid»
      خلاصه‌اش به این صورت است:
      - ابتدا رخداد error مربوط به data source را باید مدیریت کرد:
       var dataSource = new kendo.data.DataSource({
                  // ... 
                  error: function (e) {
                      window.SalesHub.OrderDetails_Error(e);
                  },
                  // ... 
              });
      با این متد
      window.SalesHub.OrderDetails_Error = function(args) {
          if (args.errors) {
              var grid = $("#orderDetailsGrid").data("kendoGrid");
              var validationTemplate = kendo.template($("#orderDetailsValidationMessageTemplate").html());
              grid.one("dataBinding", function(e) {
                  e.preventDefault();
      
                  $.each(args.errors, function(propertyName) {
                      var renderedTemplate = validationTemplate({ field: propertyName, messages: this.errors });
                      grid.editable.element.find(".errors").append(renderedTemplate);
                  });
              });
          }
      };
      که از این قالب برای نمایش خطاها استفاده می‌کند:
      <script type="text/x-kendo-template" id="orderDetailsValidationMessageTemplate">
          # if (messages.length) { #
              <li>#=field#
                  <ul>
                      # for (var i = 0; i < messages.length; ++i) { #
                          <li>#= messages[i] #</li>
                      # } #
                  </ul>
              </li>
          # } #
      </script>
  • #
    ‫۹ سال و ۴ ماه قبل، چهارشنبه ۳۰ اردیبهشت ۱۳۹۴، ساعت ۰۱:۰۷
    - هرچندتا پروژه مربوط به kendo Ui که پیوست شده بود رو دانلود میکنم  نمیتونم اجراش کنم به خاطر نبود فایل به اسم  NuGet.exe   
    - آیا امکانش هست که توی لیست نمایش چندتا فیلد نمایش داده بشه ولی توی ایجاد یه فیلد‌های دیگه هم اضافه بشه که نیاز به نمایش در ویو نباشد؟ 
    - آیا امکانش هست یه فیلد که مثلا عکس وقتی که میخوایم یه رکورد جدید بسازیم، جوری سفارشی سازی بشه که عکس دریافت کنه و یا حالا مثلا چک باکس و کمبو باکس.
    نمایش دادن عکس توی ویو رو مشکلی نداشتم و با استفاده از template تونستم درست کنم. ولی موقع ویرایش و ایجاد نمیدونم چطوری باید انجام بدم.
    • #
      ‫۹ سال و ۴ ماه قبل، چهارشنبه ۳۰ اردیبهشت ۱۳۹۴، ساعت ۰۱:۴۱
      - فایل NuGet.targets را باز کنید. مقدار تنظیم شده‌ی ذیل را در آن خواهید یافت:
       <DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">true</DownloadNuGetExe>
      به این معنا که اگر فایل nuget.exe وجود نداشت، از اینترنت دریافتش کن.
      همچنین مخزن کد مثال‌های این سری، حاوی این فایل هست و بهتر است از این مخزن کد استفاده کنید، چون حاوی مثال‌های به روز شده‌ی این سری هست که در انتهای بحث‌ها پیوست نشده‌اند.
      - تعریف فیلدها و ستون‌ها در سمت کاربر به اختیار شما است و هیچ ضرورتی ندارد که با تعداد فیلدهای سمت سرور یکی باشد. حتی می‌توانید ستون محاسبه شده‌ هم ایجاد کنید.
      - در مورد ارسال تصویر مطلب جداگانه‌ای در سایت تهیه شده‌است؛ در اینجا
  • #
    ‫۹ سال و ۲ ماه قبل، دوشنبه ۲۹ تیر ۱۳۹۴، ساعت ۲۱:۲۴
    چگونه میتوان بعد از اعمال تمام تغییرات ویرایش شده ، حذف شده و یا ایجاد شده ، فقط یک پیغام به کاربر نمایش داد که عملیات به پایان رسیده است؟ تشکر.
    • #
      ‫۹ سال و ۲ ماه قبل، دوشنبه ۲۹ تیر ۱۳۹۴، ساعت ۲۱:۳۳
      dataSource    : {
          // ....
          requestStart: function () {
              kendo.ui.progress($("#grid"), true);
          },
          requestEnd  : function () {
              kendo.ui.progress($("#grid"), false);
          }
      },
      • #
        ‫۹ سال و ۲ ماه قبل، دوشنبه ۲۹ تیر ۱۳۹۴، ساعت ۲۱:۴۳
        با تشکر.
        درحالت batch اگر هم رکوردی اضافه شده باشد و رکوردی دیگر حذف یا ویرایش شده باشد ، رویداد requestEnd به ازای آنها فراخوانی می‌شود. ولی من می‌خواهم تنها یک بار بعد از اتمام همه آنها فراخوانی شود.
        • #
          ‫۹ سال و ۲ ماه قبل، دوشنبه ۲۹ تیر ۱۳۹۴، ساعت ۲۱:۵۵
          اینطور نیست. خاصیت batch به این دلیل طراحی شده که تمام تغییرات گرید، فقط در طی یک درخواست ارسال شوند (تا سربار رفت و برگشت‌های به ازای هر تغییر، کاهش یابد و یکی شود). رویداد requestEnd هم فقط یکبار فراخوانی می‌شود. در متن، قسمت «در data source امکان تعریف خاصیتی به نام batch نیز وجود دارد » را مطالعه کنید.
  • #
    ‫۸ سال و ۸ ماه قبل، دوشنبه ۲۸ دی ۱۳۹۴، ساعت ۲۰:۳۱
    با سلام
    آیا روشی وجود دارد که  هنگام حذف رکود  یه پیام سفارشی رو  نشان بده به همراه یکی از مقادیر رکوردی رو که میخواهد حذف کنه: به  عنوان مثال:
     "ایا شما مایل به حذف این رکورد هستید:"+  مقدار یکی از ستون‌های جدول
     2- بجای پنجره حذف رکورد گرید یه پنچره سفارشی دیگه نشون بدیم
    • #
      ‫۸ سال و ۸ ماه قبل، دوشنبه ۲۸ دی ۱۳۹۴، ساعت ۲۳:۰۴
      یک مورد پیاده سازی را میتوانید در این آدرس  مشاهده کنید.
  • #
    ‫۸ سال و ۶ ماه قبل، جمعه ۱۳ فروردین ۱۳۹۵، ساعت ۱۷:۴۰

    دیتای زیر را در نظر بگیرید:

    [
    {
        OrderId: 1,
        OrderName: 'order 1'
        OrderItems: [
            {
                ProductId: 1,
                ProductName: "sample name"
            },
            {
                ProductId: 2,
                ProductName: "sample name 2"
            }
    },
    {
        OrderId: 2,
        OrderName: 'order 2'
        OrderItems: [
            {
                ProductId: 55,
                ProductName: "sample name 55"
            },
            {
                ProductId: 18,
                ProductName: "sample name18"
            }
    }
    ]

    من چطور میتونم مدلی تعریف کنم که بتوان مدل های  nested  این مدل رو پوشش بده:

    var model = kendo.data.Model.define({
        id: "OrderId",
        fields: {
            OrderId: {
                    type: "number",
                    editable: false
            },
     
            OrderName: {
                    type: "string",
                    editable: false
            },
     
            OrderItems: {
                ??????????????
            }
        }
    });

    آیا امکان تعریف مدلی به این شکل وجود دارد که بتوان در حین عملیات  CRUD  مدل های  nested  را هم تغییر داد؟ 

  • #
    ‫۷ سال قبل، جمعه ۱۷ شهریور ۱۳۹۶، ساعت ۲۰:۰۸
    جهت اطلاع

    تمام مثال‌های این سری به ASP.NET Core منتقل شدند. کدهای نهایی آن‌ها را از مخزن کد KendoUI.Core.Samples می‌توانید دریافت کنید.
    این مثال‌ها بر اساس Kendo UI Professional R2 2017 SP1 تهیه شده‌اند (فایل‌های مورد نیاز هم پیوست شده‌اند).  
  • #
    ‫۶ سال و ۹ ماه قبل، جمعه ۲۴ آذر ۱۳۹۶، ساعت ۲۳:۱۴
    در وضعیت ویرایش دسته ای، فیلدهای رکوردهای تغییر یافته به کنترلر آپدیت ارسال نمی‌شود بعبارتی پارامتر IEnumerable<Product> نال هست ولی وقتی گرید در وضعیت آپدیت دسته ای قرار ندارد پارامتر Product کنترلر آپدیت دارای مقدار است و امکان دسترسی به فیلد تغییر یافته وجود دارد. آیا باید بجز تغییر خاصیت batch: true کار دیگری نیاز است انجام شود؟
    • #
      ‫۶ سال و ۹ ماه قبل، یکشنبه ۲۶ آذر ۱۳۹۶، ساعت ۱۵:۴۸
      جهت فعالسازی صحیح ویرایش دسته ای ابتدا یک کلاس بعنوان مثال بنام ProductsRequest با خاصیتی بنام Models، نام خاصیت مهم است و حتما باید نامش Models باشد و نباید تغییری کند به دلیل نگاشت توکار و پیش فرض Kendo، ایجاد گردد.
      public class ProductsRequest
      {
          // نام این خاصیت نباید تغییر یابد
          public IEnumerable<Product> Models { get; set; }
      }

      سپس در متد آپدیت بعنوان پارامتر معرفی گردد.
      public HttpResponseMessage Update(ProductsRequest products)
      {
      از این پس پارامترهای اطلاعات ارسالی از parameterMap به این کلاس نگاشت خواهد شد و دسترسی مهیا خواهد شد. توجه داشته باشید این روش برای درج دسته ای نیاز کاربرد دارد.
  • #
    ‫۵ سال و ۴ ماه قبل، سه‌شنبه ۱۰ اردیبهشت ۱۳۹۸، ساعت ۱۷:۰۱
    با سلام
    آیا سمپل همچین مجموعه ای برای انگولار هم وجود داره؟
  • #
    ‫۵ سال قبل، سه‌شنبه ۵ شهریور ۱۳۹۸، ساعت ۱۷:۲۰
    سلام؛ هنگام حذف یک سطر با پیغام 400 یا همان BadRequest مواجه میشم و عجیب اینکه type رو بصورت xml نشون میده داخل delete به جای json تو بخش Network یعنی عکس دوم (یک لحظه اون سطر از داخل سطرها حذف میشه به محض رفرش کردن گرید دوباره نشون میده): 

    اینم کدهای بنده داخل View متناظر:

    destroy: {
                            url: function (blog) {
                                return "@Url.Action("DeleteBlog","Admin")/" + blog.id;
                            },
                            contentType: 'application/json; charset=utf-8',
                            type: "DELETE"
                        },

    و این بخش : 

     $("#report-grid").kendoGrid({
                    dataSource: blogDataSource,
                    autoBind: true,
                    scrollable: false,
                    pageable: true,
                    sortable: true,
                    filterable: true,
                    reorderable: true,
                    selectable: true,
                    editable: {
                        confirmation: "آیا مایل به حذف ردیف انتخابی هستید؟",
                        destroy: true, // whether or not to delete item when button is clicked
                        mode: "popup" // options are "incell", "inline", and "popup"

    اینم کدهای اکشن متد Delete بنده :

      [HttpDelete]
      [ValidateAntiForgeryToken]
      public async Task<IActionResult> DeleteBlog(long id)
      {
              var blog = _blogRepository.Get(id);
              if (blog == null)
                return NotFound();
                blog.IsDeleted = true;
              _blogRepository.Update(blog);
               await _unitOfWork.SaveAsync();
               return Json(blog);
      }
  • #
    ‫۵ سال قبل، دوشنبه ۲۵ شهریور ۱۳۹۸، ساعت ۲۳:۴۷
    سلام؛ من میخواهم آپلود عکس در این مثال انجام بدم آیا راهی برای این کار در core هست؟ یعنی با inset تو کار kendo ui  
  • #
    ‫۵ سال قبل، پنجشنبه ۲۸ شهریور ۱۳۹۸، ساعت ۱۶:۳۲
    در مثال دات نت کور این مساله در بخش Sample2 داخل کنترلر دو پارامتر رو(string param1, string param2) ذکر کردین که تو View همون کنترلر اشاره شده که میشه ارسال اطلاعات اضافی کرد به سمت سرور توسط این بخش ارسال اطلاعات اضافی و سفارشی به سرور در حین درخواست  . ولی من میخوام یه ای دی از نوع int رو این شکلی ارسال کنم ولی هر بار که چک میکنم نال میفرسته داخل کنترلر.

    این متد برای kendo grid بخش read  هستش داخل کنترلر :

    public IActionResult CurrentPostTags(int blogID)
    {
        var dataString = this.HttpContext.GetJsonDataFromQueryString();
        var request = JsonConvert.DeserializeObject<DataSourceRequest>(dataString);
        var tags = _blogRepository.GetAllTags(blogID).OrderBy(s => s.Id);
        var currenttags = _mapper.Map<IList<TagsViewModel>>(tags);
                if (currenttags == null)
                {
                    return NotFound();
    
                }
                return Json(currenttags.AsQueryable()
                           .ToDataSourceResult(request.Take, request.Skip, request.Sort, 
                                                           request.Filter));
    }

    که میخوام blogID رو دریافت کنم از سمت کندو گرید ولی نال میگیره هر بار. حتی یه رشته هم میفرستم باز نال برمیگردونه.

    اینم گرید بنده :

     $(function() {
                var currentTagsDataSource = new kendo.data.DataSource({
                    transport: {
                        read: {
                            url: "@Url.Action("CurrentPostTags", "Admin")",
                            dataType: "json",
                            contentType: 'application/json; charset=utf-8',
                            type: 'GET',
                            data : { blogID: @BlogID }
                            
                        },

    • #
      ‫۵ سال قبل، پنجشنبه ۲۸ شهریور ۱۳۹۸، ساعت ۱۶:۴۸
      - چون بر اساس اطلاعات header رسیده (contentType و dataType)، سیستم Binding سمت سرور، اطلاعات دریافتی را به یک JSON Object تبدیل می‌کند که این شیء نهایی، قابل انتساب به یک رشته یا عدد ساده نیست: «نکته‌ای در مورد تک پارامترها در ASP.NET Core» 
      + این اطلاعات اضافی، سمت سرور با ارث بری از DataSourceRequest قابل تعریف هستند.
    • #
      ‫۵ سال قبل، پنجشنبه ۲۸ شهریور ۱۳۹۸، ساعت ۱۶:۵۸
      - این چند سطری را هم که نوشتید، به علت استفاده‌ی از الگوی مخزن، کارآیی بسیار پائینی دارد:
       var tags = _blogRepository.GetAllTags(blogID).OrderBy(s => s.Id);
          var currenttags = _mapper.Map<IList<TagsViewModel>>(tags);
                  if (currenttags == null)
                  {
                      return NotFound();
      
                  }
                  return Json(currenttags.AsQueryable()
                             .ToDataSourceResult(request.Take, request.Skip, request.Sort,
                                                             request.Filter));
      ابتدا تمام اطلاعات یک جدول را دریافت می‌کنید. بعد این لیست درون حافظه‌ای را نگاشت می‌کنید (که اگر از الگوی مخزن استفاده نمی‌کردید، با یک کوئری قابل انجام بود). بعد آن‌ها را تبدیل می‌کنید به Queryable و در آخر متد ToDataSourceResult را بر روی آن فراخوانی می‌کنید. هدف از متد ToDataSourceResult این بوده که مستقیما روی کوئری LINQ to Entities شما فراخوانی شود (پیاده سازی dynamic linq است) و نه به این شکل. کل این عملیات باید یک کوئری شود؛ نه سه کوئری که یک مورد آن بدترین حالت واکشی کل اطلاعات از بانک اطلاعاتی است و سپس فیلتر کردن آن در طی دو کوئری سمت کلاینت. استفاده از dynamic linq (یا ToDataSourceResult در اینجا)، یعنی اضافه کردن where، take و skip به صورت خودکار به کوئری نهایی شما؛ یعنی عدم نیاز به تنظیم دستی هرباره‌ی این‌ها و ساده شدن کوئری نویسی. هدف آن هم اعمال به کوئری اصلی LINQ to Entities است تا در SQL نهایی ظاهر شود. اینجا است که الگوی مخزن شما نه تنها کمکی نکرده، بلکه با مخفی کردن کوئری اصلی LINQ to Entites و بازگشت کل اطلاعات به صورت درون حافظه‌ای، کارآیی برنامه را هم به شدت کاهش داده.
      - مثالی که اینجا ارائه شده جهت سهولت کار و توضیح و همچنین کاهش بار ذهنی خواننده، از یک منبع داده‌ی درون حافظه‌ای ساده‌ی بدون نیاز به بانک اطلاعاتی استفاده می‌کند. نه اینکه کدهای نهایی شما باید دقیقا به این شکل باشد.
      • #
        ‫۴ سال و ۱۱ ماه قبل، شنبه ۲۰ مهر ۱۳۹۸، ساعت ۱۴:۰۳
        ممنونم از راهنمایی شما.

        البته کل اطلاعات واکشی نمیشه اینجا. در حقیقت فقط تگ هایی با اون blogID مشخص آورده میشن(داخل شرط کوئری که در blogRepository هست چک میشه) که در سنگین‌ترین حالت به 10 رکورد هم نمی‌رسه. 
        ولی خواهشی که بنده دارم این هستش که اگر امکانش هست این موردی که میفرمایید رو که با یک کوئری قابل انجام هست رو بیشتر توضیح بدید.یا حداقل مثالی رو بزنید. خب من توی مقالات قبلی شما و همچنین مقالات سایت مایکروسافت خوندم که خود مایکروسافت الگوی Repository رو با dbContext پیاده سازی کرده. ولی خب توی اکثر نمونه هایی که میبینم چه در این سایت چه در سایت‌های دیگه همه میان دوباره الگوی مخزن رو استفاده میکنند.