18
votes

I'm still learning Jquery and a bit confused with the task I have on my hands.

Seems like a simple task... I have a box that I want to populate with Options on click. I don't want it to be populated on page load, only when someone actually requests to see the list. Also it has to be populated only once. I really dont want the request to go out EVERY time someone expands the list.

I imagine that I'll probably have a function call in my Select element

<select id="usersList" name="usersList" onclick="getUsers()">

And then have a Javascript getUsers() function make a call to my Json GetUsers() ActionMethod to get that list. How ?

Something like...?

function getUsers()
{
 getJSON("/Users/GetUsers", null, function (data){}
}

or JQuery?...

$("usersList").click(
  $.getJSON("/Users/GetUsers", null, function (data) {}
  )

I should mention that I saw this post: populate selectlist with json data in JQuery when the selectlist is loaded (not the document)

But I need help putting it all together please. Thank you in advance!

2

2 Answers

39
votes

Here is the javascript I would use to populate the select box.

$.getJSON("/Users/GetUsers", null, function(data) {
    $("#UsersList option").remove(); // Remove all <option> child tags.
    $.each(data.Users, function(index, item) { // Iterates through a collection
        $("#UsersList").append( // Append an object to the inside of the select box
            $("<option></option>") // Yes you can do this.
                .text(item.Description)
                .val(item.Id)
        );
    });
});

I would recommend that you trigger this on the page load and not when the user clicks the select box. jQuery AJAX is asynchronous by default (as it should be) so there will be a moment or two where the select box will be empty and this may greatly confuse the user.

Was this the extent of your question or did you need assistance with the MVC side as well? If you're using ASP.Net MVC there is actually a specific result type of JsonResult which makes creating JSON controller methods a bit simpler since they don't require corresponding views. It also allows you to use anonymous data structures which makes method specific projections a bit simpler.


EDIT Here is the basic method for returning a JSON structure the jQuery code above will understand. Note that the properties u.Username and u.ID depend on your Users object.

[HttpPost] 
public JsonResult GetUsers() { 
    return Json(new {
        Users = from u in _usersRepository.Get()
                select new { Description = u.Username, ID = u.ID }
    }); 
}

I would recommend however that you abandon this approach as soon as possible and go with a standard JSON message structure. The one I use is something like this:

{
    Success: bool,
    LoggedIn: bool,
    ClientErrors: [
        { Number: int, Description: string, Parameter: string },
        { Number: int, Description: string, Parameter: string }...
    ],
    ServerErrors: [
        { Id: int, Message: string },
        { Id: int, Message: string }...
    ],
    Data: {}
}

Here are a few reasons for doing this:

  1. Make no mistake, your JSON method library is a protocol of sorts and as such it benefits from a standard header.
  2. Error handling benefits the most from this. Having a consistent method for letting the user know something went wrong is invaluable down the road.
  3. Differentiating between client errors (bad username, incorrect password, etc) and server errors (database offline) is very important. One the user can fix, the other they cannot.
  4. Client Errors should return not only a message but the parameter in the method which cause it (if it applies) so that you can easily display these error messages next to the appropriate input fields.
  5. Client Errors should also provide a unique number (per method) which identifies the error. This allows for multilingual support.
  6. Server errors should provide the Id of the error which was logged. This way you can allow the user to contact support and reference the particular error they are running into.
  7. The loggedin boolean allows any page which uses methods that require authentication to easily redirect the user back to the login screen if necessary since a redirect action result of a JSON method will have no effect.
  8. Finally the Data field is where the method specific data should be provided.

By no means should you consider my structure as the way to do it. Clearly your application needs may differ greatly from mine. Consistency, more than any particular structure is the lesson here.

EDIT: 06/01/2016 - Seeing as people are still looking at this answer. With regard to populating the drop down I would recommend looking into using a two way binding framework. Personally I prefer Knockout.JS for how easy and lightweight it is although Angular.JS would do the job as well. Aside from that the rest of this answer is still fairly up to date.

EDIT: 8/10/2016 - Code was missing a comma.

5
votes

I would use the jQuery option.

// You are missing the new anonymous function call
$("#usersList").click(function() {
    // If the select list is empty:
    if ($(this).find("option").size() > 0) {
        // Documentation on getJSON: http://api.jquery.com/jQuery.getJSON/
        $.getJSON("/Users/GetUsers.php", null, function (data) {
            $.each(data.items, function(i,item){
                // Create and append the new options into the select list
                $("#usersList").append("<option value="+item.id+">"+item.yourName+"</option>");
            });
        });
    }
});

Since append() operations are relatively 'expensive', you could also just build a string that contains the info and append it just once like this:

var collaboration = "";
$.each(data.items, function(i,item){
    collaboration += "<option value="+item.id+">"+item.yourName+"</option>";
});
$("#usersList").append(collaboration);
...

Here is a jsfiddle that demonstrates how to determine if the select list is empty.