Multiselect and form, not sending values back

9 posts, 0 answers
  1. Alberto
    Alberto avatar
    71 posts
    Member since:
    May 2012

    Posted 16 May 2014 Link to this post

    Hi guys,
    I have a mvc view (still a pretty standard one) to edit one of my entities..

    @using (Ajax.BeginForm("Edit", "Role",
           new AjaxOptions() { HttpMethod = "POST", UpdateTargetId = "ajaxRoleEditForm", OnSuccess = "OnRoleUpdated" }))
       {
     
           @Html.AntiForgeryToken()
           @Html.ValidationSummary(true)
     
           <fieldset>
               <legend>ROLE_T005</legend>
     
               @Html.HiddenFor(model => model.ID)
     
               <div class="editor-label">
                   @Html.LabelFor(model => model.Name)
               </div>
               <div class="editor-field">
                   @Html.EditorFor(model => model.Name)
                   @Html.ValidationMessageFor(model => model.Name)
               </div>
     
               <div class="editor-label">
                   @Html.LabelFor(model => model.Description)
               </div>
               <div class="editor-field">
                   @Html.EditorFor(model => model.Description)
                   @Html.ValidationMessageFor(model => model.Description)
               </div>
     
               <div class="editor-label">
                   @Html.LabelFor(model => model.Functions)
               </div>
     
               <div class="editor-field">
                   @Html.EditorFor(model => model.Functions)
               </div>
               <p>
                   <input type="submit" value="Save" />
               </p>
           </fieldset>
       }

    the model is a view model because the actual table (using EF) has a cross table to a child entity and I dont want to bother with it.
    so my wiew model is:
    public class RoleViewModel
       {
           public int ID { set; get; }
     
           public string Name { set; get; }
     
           public string Description { set; get; }
     
           [UIHint("FunctionMultiSelectTemplate")]
           public IList<FUNCTION_T008> Functions { set; get; }
       }

    and the custom template for the list of functions is:
    @model IList<Lme.WQ2.AccessControl.Dal.FUNCTION_T008>
     
    @(Html.Kendo().MultiSelect()
        .Name("FunctionMultiSelectTemplate")
        .Placeholder("Select functions...")
        .BindTo(ViewBag.Functions)
        .Value(Model)
        .DataTextField("NAME")
        .DataValueField("ID")
        )

    at last my action looks like:

    public ActionResult Edit(int id = 0)
            {
                ROLE_T005 role_t005 = db.ROLE_T005
                    .Include(x => x.ROLE_FUNCTION_T010)
                    .Include(x => x.ROLE_FUNCTION_T010.Select(y => y.FUNCTION_T008))
                    .SingleOrDefault(x => x.ID == id);
     
     
                RoleViewModel roleViewModel = new RoleViewModel()
                {
                    ID = role_t005.ID,
                    Name = role_t005.NAME,
                    Description = role_t005.DESCRIPTION,
                    Functions = role_t005.ROLE_FUNCTION_T010.Select(x => x.FUNCTION_T008).ToList()
                };
     
     
                ViewBag.Functions = db.FUNCTION_T008.AsEnumerable();
     
                if (role_t005 == null)
                {
                    return HttpNotFound();
                }
                return View(roleViewModel);
            }

    now, when I hit the save button of the view, the function list is always null or empty...
    What am I doing wrong?
    Thanks
    Fabio
  2. Georgi Krustev
    Admin
    Georgi Krustev avatar
    3707 posts

    Posted 16 May 2014 Link to this post

    Hello Fabio,

    I would suggest you check this code library, which shows how to bind MultiSelect and then post its values to the server. The key point here is that the name of the widget should be same as the model property as this is the only way for the ASP.NET MVC DefaultModelBinder to map the posted values to the view model.

    Regards,
    Georgi Krustev
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
  3. UI for ASP.NET MVC is VS 2017 Ready
  4. Alberto
    Alberto avatar
    71 posts
    Member since:
    May 2012

    Posted 16 May 2014 in reply to Georgi Krustev Link to this post

    ok but in the example you posted, the returned values are "just" ids (int)...
    is it not possible to return the whole class list? 
  5. Georgi Krustev
    Admin
    Georgi Krustev avatar
    3707 posts

    Posted 19 May 2014 Link to this post

    Hello Fabio,

    The MultiSelect widget uses a SELECT element (<select multiple="multiple></select>), which posts only the selected values. If you would like to post the whole objects, then you will need to do it manually. You can get the selected data items using widget's dataItems method. To post the data, you can use jQuery.ajaxmethod.

    Regards,
    Georgi Krustev
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
  6. Alberto
    Alberto avatar
    71 posts
    Member since:
    May 2012

    Posted 03 Jun 2014 in reply to Georgi Krustev Link to this post

    Hi Georgi,
    I'm trying to figure this issue out...

    I changed a little bit my structure...I'm not working with the ViewModel object anymore..

    here is my new template:
    @model ICollection<USER_ROLE_T007>
     
    @(Html.Kendo().MultiSelect()
        .Name("USER_ROLE_T007")
        .Placeholder("Select roles...")
        .BindTo(ViewBag.Roles)
        .Value(Model.Select(x => x.ROLE_T005))
        .DataTextField("NAME")
        .DataValueField("ID")
        )

    and here is my razor:
    <div class="editor-label">
                    @Html.LabelFor(model => model.USER_ROLE_T007)
                </div>
                 <div class="editor-field">
                    @Html.EditorFor(model => model.USER_ROLE_T007)
                    @Html.ValidationMessageFor(model => model.USER_ROLE_T007)
                </div>
    and I linked the template with the UHint dataAnnotation attribute.
    As a reminder USER_ROLE_T007 is the cross-table entity.
    On visualization everything works fine.
    I can also add items (roles) to the multi-select.
    When I hit the save button and the code arrives to the update action it doesn't pass the "ModelState.IsValid" check
    and the reason is that the multiselect (as you explained in your post) returns only ids...

    for your reference the exception raised is 
    The parameter conversion from type 'System.String' to type 'USER_ROLE_T007' failed because no type converter can convert between these types.

    Do you know If there is any workaround or any way to intercept the validation and custom convert the id to the class??
    Consider that the object posted back to the server always has its list (cross table entity) empty...even if it contained some element in the first place...

    Thanks
    Fabio
  7. Alberto
    Alberto avatar
    71 posts
    Member since:
    May 2012

    Posted 04 Jun 2014 in reply to Alberto Link to this post

    UPDATE:

    I managed to remove cross classes from entity model.
    So now each class is related to the other one directly; In this case eneity USER_T001 contains a list of ROLE_T005.

    so now my multiselect is bound to roles...
    the issue remain the same... Model.isValid is false...same error..
    always ids post back to the server... but now I'm more optimistic about a possible solution since it seems now a common scenario.

    Thanks
  8. Daniel
    Admin
    Daniel avatar
    2117 posts

    Posted 05 Jun 2014 Link to this post

    Hello Fabio,

    I am not sure if I understand the described changes. Does the list bound to the multiselect still consists of objects? If yes and the entire dataItems cannot be posted via Ajax in your scenario then you can use one of the following approaches to bind the property when it is posted with a form:
    • exclude the property from the model binding and add a separate parameter for the ids collection e.g.
      public ActionResult Action([Bind(Exclude = "CollectionPropertyName")]MyModel model, IEnumerable<int> CollectionPropertyName)
      {  
          if (CollectionPropertyName != null)
          {
              model.CollectionPropertyName = CollectionPropertyName.Select(id => new CollectionObjectType
              {
                  ID = id
              });
          }
    •  Implement a custom model binder for the model type or for the collection type and create a collection of objects when a comma separated string with the IDs is posted to the server.


    Regards,
    Daniel
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
  9. Alberto
    Alberto avatar
    71 posts
    Member since:
    May 2012

    Posted 06 Jun 2014 in reply to Daniel Link to this post

    Hi Daniel,
    Yes the list bound to multiselect still consists of objects.

    I had a look to both your suggestions and I think that the first suits me better in this case.
    Now I got my Model.IsValid check as true; I don't get why I get the state of the object as detached though...
  10. Daniel
    Admin
    Daniel avatar
    2117 posts

    Posted 10 Jun 2014 Link to this post

    Hi,

    Could you clarify what you mean by:
     get the state of the object as detached
    If you are using an ORM tool and the action parameter is in detached state then this behavior is expected. You should explicitly attach the model to the context.

    Regards,
    Daniel
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
Back to Top
UI for ASP.NET MVC is VS 2017 Ready