简体   繁体   中英

Pass custom collection object from Controller to View with JQuery

I have a custom object that derives from IEnumerable. This collection is pretty complex because it contains object which themselves contain collections of other objects. Simply put, it is a multiple dimension array.

I have a drop down list on my view that gets populated with a server call of items, and when a certain item is selected, it calls the server to get the associated collection object for that item.

I inherited this code and initially when the first drop down was selected a second drop down is enabled and the user selects a single item. The second drop down is populated with the items in the collection (the collection itself is parsed through to simply get the name and id number of the item).

Now, instead of a second drop down, I want to actually return the collection to the view and have my view loop through and display the contents of the collection and all that good stuff.

My question is how can I transfer this collection object from my controller to my view.

Here is the code in the controller which will grab the collection based on the value of the drop down.

public ActionResult GetWorkbooks(string term, int projectId = -1)
    {
        if (this.SelectedProject != projectId)
        {
            try
            {
                WorkBookDataManager dataManager = new WorkBookDataManager();
                this.WorkbookColl = dataManager.GetWorkBooksById(null, projectId, null);
                this.SelectedProject = projectId;
            }
            catch (Exception exc)
            {
                log.Error("Could not load projects", exc);
            }
        }

        return this.View("_Workbook", this.WorkbookColl);
    }

This code will return a partial view with the collection as a model. But how can I use that with the existing JQuery code when the drop down has a value selected?

Here is the drop down code:

// Populate the first drop down
var loadProjects = function (request, response) {
    $.ajax({
        url: $("#projects").attr("data-vs-autocomplete"),
        dataType: "json",
        type: "POST",
        data: { term: request.term }
    })
    .always(function (data, status) { getResponse(response, data, status); });
};

// If the first drop down has an item selected enable the second drop down
var projectSelected = function (event, ui) {
    var projectId = $("#projects").data(VS_AUTOCOMPLETE_VALUE);

    var enable = projectId ? false : true;
    /*$("#workbooks").prop('disabled', enable);

    $("#workbooks").val("");
    $("#workbooks").data(VS_AUTOCOMPLETE_VALUE, "");
    $("#workbooks").data(VS_AUTOCOMPLETE_TEXT, "");*/
    $("#workbook").html("<p>No workbook selected</p>");
};

// Function to get the second drop down items
// This is the function I think needs to be modified to accept the collection object from the server
var loadWorkbooks = function (request, response) {
    $.ajax({
        url: $("#workbooks").attr("data-vs-autocomplete"),
        dataType: "json",
        type: "POST",
        data:
            {
                term: request.term,
                projectId: $("#projects").data(VS_AUTOCOMPLETE_VALUE)
            }
    })
        .always(function (data, status) { getResponse(response, data, status); });
};

// Second drop down -> This needs to be removed
var workbookSelected = function (event, ui) {
    $("#workbooks").blur(); // this prevents the workbook dropdown from focusing.
    LoadWorkbook();
};


// These functions populated the drop downs with items
Autocomplete($("#projects"),
   { autoFocus: true,
       minLength: 0,
       source: loadProjects,
       select: projectSelected
   });

Autocomplete($("#workbooks"),
    { autoFocus: true,
        minLength: 0,
        source: loadWorkbooks,
        select: workbookSelected
    });

I want to make this simple so if there is a better way to do all of this and restructure the controller and/or jquery, I am all ears (eyes).

Let me know if more information is needed or if anything is unclear. Thanks

"Best practice" here is single responsibility principle, ie separate actions for getting the data that should be displayed in dropdown and the same data that is rendered as partial view. Basically all you need is a method to retrieve the model, and one action that serializes the model and return in form of JSON, another - returns partial view. Controller:

private Workbook GetWorkbooksByProject(int projectId)
{
    WorkBookDataManager dataManager = new WorkBookDataManager();
    var workbookColl = dataManager.GetWorkBooksById(null, projectId, null);   
    return workbookColl;
}

public JsonResult GetWorkbooks(int projectId)
{
    var model = GetWorkbooksByProject(projectId);
    return Json(model, JsonRequestBehavior.AllowGet);
}

public ActionResult WorkbooksList(string term, int projectId = -1)
{
    if (this.SelectedProject != projectId)
    {
        try
        {
            this.WorkbookColl = GetWorkbooksByProject(projectId);
            this.SelectedProject = projectId;
        }
        catch (Exception exc)
        {
            log.Error("Could not load projects", exc);
        }
    }

    return this.View("_Workbook", this.WorkbookColl);
}

From client side you must change the url to post data to GetWorkbooks action method and you are good to go.

Advantages of this approach is that populating the dropdown will not execute any other logic than retrieving workbooks list and at client side you can now easily leverage any binding framework (eg KnockoutJS) or plain javascript to render your model, even if your html markup will be changed in future from simple dropdown to more complex ui.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM