Paul
Paul

Reputation: 12799

Best way to Update a strongly typed View(MVC 3.0)

I have a strongly typed Category View, showing all Category (in a grid) ... Under that grid I have the fields to Add/Edit a new Category details: several textbox and radiobox, like : - Category Name - Category Description - Category Imagem etc

So, When the user select a Category on Grid, it fills the fields via JQuery Ajax...

  $.ajax({
        url: '/Category/Get',
        type: 'POST',
        dataType: 'json',
        data: {
            idCategory: ...
        }
    })
    .success(function(category,success) {                
        // Update TextBox fields
        $(".ajax").each(function(){
            $(this).val(category[$(this).attr("id")]);
        });
        //Other fields ...             
     })      

My Controller

[HttpPost]
public ActionResult Get(string idCategory)
{
     if (ModelState.IsValid)
     {
         var _category = _categoryRepository.Get(Convert.ToInt16(idCategory));

         if (Request.IsAjaxRequest())
             return Json(_category);
         return RedirectToAction("Index");
     }
     if (Request.IsAjaxRequest())
         return Json(new Category());
     return View();
 }

It´s working fine !

But I´d like to know if it is the best way to do that... It is possible to do it another way? Maybe using Ajax.BeginForm?

Thanks

Paul

Upvotes: 1

Views: 2352

Answers (1)

Ryan
Ryan

Reputation: 4313

Two possible ways to do this in my view.

1) Return a partial view with the category fields in it each time you change the selected category in the grid. Don't bother with JSON.

2) If you want to use JSON (which is how I'd probably do it), then use a framework like Knockout.JS to handle the binding. It would look something like this:

<div id="current">
    Name: <input type="text" data-bind="value: Name"/><br/>
    Description: <input type="text" data-bind="value: Description"/><br/>
    <input type="button" value="Save" data-bind="click: Save" />
</div>

// javascript viewmodel w/ observable properties (except Id)
var Category = function(original) {
this.Id = original.Id;
this.Name = ko.observable(original.Name);
this.Description = ko.observable(original.Description);

this.asJson = function() {
    return {
        Id: this.Id,
        Name: this.Name(), // call observables as method to get underlying value
        Description: this.Description()
    };
};

this.Save = function() {
    $.post("/Category/Update", $.toJSON(this.asJson()));
};
}

$.post('/Category/Get', { idCategory: ... }, function(response) {
    var viewModel = new Category(response);
    ko.applyBindings(viewModel, $("#current"));
}, "json");

Your action could probably be simplified to

[HttpPost]
public ActionResult Get(int idCategory)
{
    var category = _categoryRepository.Get(idCategory) ?? new Category();
    return Json(category)
}

Then to save just do whatever you normally do on the server

[HttpPost]
public ActionResult Update(Category updated)
{
    var category = _categoryRepository.Get(updated.Id);
    // todo: update category with values from updated model
}

Edit

If you don't want to call applyBindings multiple times, you can use templates instead. (I didn't test this code but it should be very close.)

<div id="current" data-bind="template: {name: 'categoryTemplate', data: Current}"/>
<input type="button" value="Save" data-bind="click: Save" />

<script type="text/html" id="categoryTemplate">
    Name: <input type="text" data-bind="value: Name"/><br/>
    Description: <input type="text" data-bind="value: Description"/>
</script>

// javascript viewmodel w/ observable properties (except Id)
var Category = function(original) {
    this.Id = original.Id;
    this.Name = ko.observable(original.Name);
    this.Description = ko.observable(original.Description);

    this.asJson = function() {
        return {
            Id: this.Id,
            Name: this.Name(), // call observables as method to get underlying value
            Description: this.Description()
        };
    };
}

var viewModel = 
{
    Current = ko.observable({}),
    Save = function() {
        $.ajax({
                url: "/Category/Update", 
                data: $.toJSON(this.Current().asJson()),
                type: "POST",
                contentType: "application/json; charset=utf-8"
            });
    }
};

$.post('/Category/Get', { idCategory: ... }, function(response) {
    viewModel.Current(new Category(response));
}, "json");

$(function(){
    ko.applyBindings(viewModel, $("#current"));
});

Upvotes: 2

Related Questions