CSLA 4.0 MVC CslaModelBinder and child collections

CSLA 4.0 MVC CslaModelBinder and child collections

Old forum URL: forums.lhotka.net/forums/t/9419.aspx


j0552 posted on Monday, August 23, 2010

Hi

I don't seem to be able to get the model binder to add and remove items from a child collection. Updates work, e.g.:

 [AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, FormCollection collection)
{
    collection.Add("Resources[0].Role", "1"); // current value is 3. update works
    collection.Add("Resources[1].Role", "2"); // need to add a new item for 2. nothing happens
   
    var project = Project.GetProject(id);

    if (TryUpdateModel(project) && SaveObject(project, true))
    {
        return RedirectToAction("Index");
    }
   
    ViewData.Model = project;
    return View();
}

Shouldn't the model binder call list.Add and list.Remove depending on the contents of the current list and the keys and values in the MVC FormCollection?

Many thanks
Andrew

j0552 replied on Monday, August 23, 2010

Maybe that should be list.AddNew() and list.RemoveAt(index). It looks like the DefaultModelBinder clears the list first which wouldn't work very well for CSLA I think.

What's the thinking behind BindCslaCollection? It only loops throught the existing collection so can't add new items.

Hmmm.

xAvailx replied on Monday, August 23, 2010

Which version of CSLA? 3.8 didn't have support for collections IIRC.

xAvailx replied on Tuesday, August 24, 2010

Heh, sorry I didn't see the 4.0 on the subject :) haven't used 4.0 yet so can't help, but reading down the thread, I do agree that it is something that would be nice to have (add/remove). I do a lot of removing / adding client side and currently handle that by going through the form collection and adding/removing. 

rasupit replied on Monday, August 23, 2010

I was considering adding add/remove collection during proof of concept (see http://cslacontrib.codeplex.com/SourceControl/changeset/view/74794#986703  BindCslaCollectionModel) but decided that at framework level is a little dangerous. Moreover, in MVC pattern is more natural to have Add and Remove action method and not combine these actions into one Edit action method.

Here is the test script describing what the model binder can currently do: http://www.lhotka.net/cslacvs/viewvc.cgi/core/trunk/Source/Csla.Web.Mvc.Test/ModelBinderTest/CslaModelBinderTest.cs?revision=4821&view=markup

HTH,

Ricky

j0552 replied on Tuesday, August 24, 2010

Hi rasupit

I understand what you are saying about Add and Remove being separate actions. That does makes sense except when, like me. you are adding and removing items client-side. Also it means I must maintain the state of the object between page requests. That's not the end of the world.

The thing is that as the default model binder deals with add and removes it feels right to me that the Csla version should do the same. If you've already taken care of adding and removing in previous actions then it won't matter anyway. I don't think it's dangerous. You've got to build in enough validation to stop dodgy requests busting the object anyway.

That's just my opinion anyway.

Cheers
Andrew

rasupit replied on Tuesday, August 24, 2010

You should be able to separate the action methods even when adding/removing items from client side.  I have the example how you call an action method using jquery like the following:  http://cslacontrib.codeplex.com/SourceControl/changeset/view/74794#986708

        $("form", newpnl).submit(function(e) {
e.preventDefault();
$.post(this.action, $(this).serialize(),
function(result) {
if (result.Success) {
var item = $(tmplt).appendTo("#role-list");
$("h3", item).text(result.Data.Name);
$("input", item).val(result.Data.Id);

newpnl.dialog("close");
}
else {
alert(result.Messages);
}
}
);
});

$("a.delete").live("click", function() {
var item = $(this).parent("li");
$.post('<%=Url.Action("Delete", "Roles")%>', { id: $("input:hidden", item).val() },
function(result) {
if (result.Success) {
item.remove();
}
else {
alert(result.Messages);
}
}
);
});

The default model binder does deal with add and removes however,
you would've use this against your view-model and not against your model right?. ;).
I get it that my statement was pretty subjective here,
and you should be allowed to run with scissor, especially on asp.net MVC.
During the proof of concept I found is not easy to implement this for csla object.
What I was trying to say was that this features was on the list but not make past
my wish list to pursue after weighing in all these factors.

Thanks,
Ricky

xAvailx replied on Tuesday, August 24, 2010

Hi Ricky,

>> The default model binder does deal with add and removes however, <<

The problem we found with the default model binder is that it appears it removes all items from the collection and then re-adds new ones from the posted values. Which ofcourse then results in items in the deleted list and those get deleted and persisted again.

 

xAvailx replied on Tuesday, August 24, 2010

One more thing regarding client side add/remove. I am not sure if this is the OP case, but for me I add / remove items in the DOM. Nothing gets persisted until user "Saves". At that time we look at what is posted and update our models accordingly.

j0552 replied on Wednesday, August 25, 2010

Hi

I agree with xAvailx, we need the option of adding and removing from the object one at a time or by a batch with one controller action. As we know it's not really acceptable to clear the Csla collection first which makes things more difficult. As a compromise I clear the list only when the count with the form values is not the same as the collection count. That way the collection doesn't get dirty if there are no changes.

I vote to keep it on the wish list in the hope that a solution gets into production soon.

Thanks
Andrew

 

rasupit replied on Wednesday, August 25, 2010

The list I described was my personal list to I would like to pursue through proof of concept. As for wish list to be implemented on CSLA, this will be solely on Rocky's decision.

One challenge I would can see is to be able to instantiate csla object, because having to just call AddNew is not a complete solution unless overriding AddNewCore is a requirement in CSLA.  However, it should be a good challenge to pull this off.

Ricky

RockfordLhotka replied on Wednesday, August 25, 2010

I would think that calling AddNew would be fine. In CSLA 4 there's always a default implementation of AddNewCore that just uses DataPortal.CreateChild, so in general it should work.

gyob00 replied on Thursday, December 08, 2011

I modified CslaModelBinder.cs to support doing it all at once. You need to use the Microsoft form element naming convention ie. Objectname[0].IsNew and include the IsNew, IsDeleted stuff. I'm not sure what all the repercussions are, so I'm putting it out there. see my code on this post:

http://forums.lhotka.net/forums/p/10770/50675.aspx#50675

garybr replied on Monday, August 23, 2010

what object type if your view bound to? Project? does the view object also contain the child collection or is that only in the controller?

Copyright (c) Marimer LLC