Look-up with multi-select

Dec 18, 2010 at 9:15 PM

Hi!

I'm curious if there is a possibility to have a view model which has a multiselect IEnumerable property?

e.g. In my case I have a GroupModel which has a List<Invitee> property, so I have the necessity to invoke Look-up with multi-select for the Invitees... Do you support this?

Tnx!

Goran

Dec 18, 2010 at 9:39 PM

Hi,

So, you want to have a ViewModel with

[Lookup(Multiselect = true)]

IEnumerable<int> Invitees { get; set; }

and the user would open the lookup, search for ppl, and choose more then one somehow,

search for John Smith, choose him, after search for somebody else, and choose him/them also, and when the users presses ok,

all the chosen ones will be set as value for this property,

are my assumptions correct, please confirm

Dec 18, 2010 at 9:46 PM

Yes, exactly that... Do you support this [Lookup(Multiselect = true)]?

tnx for the quick reply!

Dec 18, 2010 at 9:47 PM

I forgot to mention, in my case would be IEnumerable<Guid> Invitees { get; set; }... I don't know it this makes a difference...

Dec 19, 2010 at 2:37 AM

int, guid, doesn't matter just like with everything else I just let the mvc ModelBinder to do it's job,

I'm not supporting Multiselect right now, but I could do this in the near future,

btw, how do you think all the selected values should be displayed when the lookup popup is closed, right now is a disabled textbox, and it's enought for a single value, but with multiselect you could have 10 selected things, should it be a textarea, label, something else ?

Dec 19, 2010 at 11:27 AM

Well, I don't think it makes sense to display the values of the property when the popup is closed, because sometimes there could be a lot of values... Instead it can be used a proper label displaying a message like "Choose..." or similar...

Also in the popup, now there is a single table for browsing/searching and displaying the selected objects... In the case of multi-select I think it would make more sense to have two grids (one for browse/search and one for displaying the selected items) and when something is selected within the browse/search table, should be added in the selected items table and vice versa. The idea with 2 grids is to have better overview of the already selected items.

This multi-select look-up would really be "nice to have".

Dec 19, 2010 at 12:29 PM

as for the grid I had kinda the same idea to drag and drop from one to another, but about the thing after the popup is closed I'm not really sure if this is a good idea to just just have a text like "value selected" instead of what really is selected

Jan 13, 2011 at 2:03 PM

try the new version, lookup now has multiselect, in the lookup controller you have a GetMultiple Action and if you don't want to display all the values after the popup is closed just do there

return Json(new[]{new{Text = "a lot of stuff selected"}});

but if you want to show, something like:

return Json( source.Select(o => new{ Text = o.Name }));

Jan 14, 2011 at 9:28 AM

Tnx for letting me know... Next week I'll have more time to check it out...

Btw does the multi-select supports paging too. In the case of my application it would be useful this option, since the number of elemsents that are to be selected is pretty large. Although I'm aware that the search option helps, but paging would be helpful as well

Tnx in advance!

Jan 14, 2011 at 1:26 PM

yes, it has paging and this is shown in the live demo

paging for the top part where you search, not for the selected items

Jan 18, 2011 at 9:52 PM

How do u pass a parameter to the search form that can be used in the search method within a repository method which is parameter-dependable?

e.g.

I have a method

Repository<User>.GetFriends(Guid ofUserId) (1)

or

Repository<User>.GetFriends(param1, param2, ..., param3) (2)

in the repository, which I want to use in a multi-select lookup.

Your current model only uses Repository.GetAll() and it doesn't have any predefined parameter which is not editable (selectable) by the user itself, but it is passed by the application depending on the User's profile that it currently viewed.

How would u pass parameters to a repository method of type (2) within a multi-select lookup?

I hope u understand what I mean, if not pls let me know, I'l try to explain it a little bit better.

Tnx, Goran

Jan 19, 2011 at 6:56 AM

you could have

 public ActionResult Search(string fname, string lname, int? someId, int? page = null){

//and here you can do whatever you want

repo.GetFriends(someId)

or

repo.GetFriends(fname, lname, someId, page)

}

Jan 19, 2011 at 10:20 AM

So far so good, but how do u map the value of "someId" with the search function parameter.

I guess you would define in your searchForm something like:

First name:

<input type="text" name="fname" >

Last name:

<input type="text" name="lname" >

<input type="hidden" name="someId" >

Now my question is how do I set this hidden field "someId" in the searchForm? This control doesn't have any model behind and even if it did, I don't invoke renderPartial of this control, but instead this is done by the multi-select lookup.

As I understand, the fields in the searchForm control are always meant to be set by the user who searches and there is no way to set a parameter as a hidden field by the application itself. Am I correct on this one or if not, how is this done?

Tnx

 

Jan 19, 2011 at 11:56 AM

yes, you are correct,

do you need something like parentId, like the Autocomplete and AjaxDropdown have,

or do you need much more than just one parent field?

Jan 19, 2011 at 12:16 PM

Basically what we build is a social network like FB.

So e.g. when a certain user creates a Group, he should be able to invite all his friends without the people that are already members of the Group.

In the repository we have a method: Rep.GetFriends(Guid userId) and also Rep.GetMembersOf(Guid groupId) and then we exclude those friends that are already members of the group. All this should be done in the Search method of the Multi-select lookup in order to allow the user to select invitees. Thus it implies we need to set in the parameters userId and groupId in advance.

This is just a simple scenario, but I can imagine that there is a necessity to set even more parameters into the Search method as a prerequisite of some repository methods.

What is your impression about this feature? Do you plan to add it soon?

Jan 19, 2011 at 12:25 PM

I think this should be possible, I'll probably add it soon

 

as for the userId I think you should be able to get from User.Identity (the logged user)

repo.GetInvitees(userId, groupId);

Jan 19, 2011 at 2:36 PM
Edited Jan 19, 2011 at 2:36 PM

I have an idea,

what if in searchForm.ascx you put this:

<input id='sGroupId' name='groupId'  type='hidden'/>

<script>

$('#sGroupId').val($('#groupId').val());// you have an <input id='groupId' somewhere in the html

</script>

so now you can put public ActionResult Search(int groupId ....

 

please let me know if it did it

Jan 20, 2011 at 4:19 PM
This could work, although it's not very clean approach. Nevertheless, tnx for the suggestion.
Jan 22, 2011 at 5:21 PM

indeed,

do you think something like below would be ok ?

<input id="userId"  type="hidden".../>

<input id="groupId"  type="hidden".../>

@Html.Lookup("Invitees", additionalData: new[]{"userId","groupId"}

and than in the search action you would get

public ActionResult Search(string search, int userId, int groupId)

 

Jan 22, 2011 at 11:12 PM

the problem with this approach is that the parameters (userId and groupId) are static. In other words if I have a table with rows of users and in for each row (user) I want to enable lookup for "invite friends", then this wouldn't work.

You are right, in the case scenario I mentioned before, this would work. But I think in general, and I can also think of more similar scenarios, where it is required something more flexible than predefining the parameters (userId, groupId) within certain view. 

Maybe if there was something like:

@Html.LookupFor(x => x.Invitees, additionalData: new[]{"userId","groupId"})

What do u think of that? How doable is this? Or you already thought about the same with the previous suggestion?

Jan 23, 2011 at 4:10 AM

I'm sorry, I'm a bit confused, what do you consider a problematic approach ?

and

"Maybe if there was something like:

@Html.LookupFor(x => x.Invitees, additionalData: new[]{"userId","groupId"})"

that's what I just asked, but if to think about the table than that's not the best approach, because  additionalData ids can't be used as names for parameters in the search action because in the table they will be different each time so instead I think I should use a dictionary

<li>

@Html.HiddenFor(o => model[0].GroupId) 

@Html.HiddenFor(o => model[0].UserId)

@Html.LookupFor(x => model[0].Invitees, additionalData: new Dictionary<string,string>{{"_0__UserId","userId"}{"_0__GroupId","groupId"}})

</li>

this way for each row different ids will be used but in the Search action you will always get userId and groupId

Jan 23, 2011 at 9:46 PM

Can it be done this way:

var int i = 0;

foreach (var group in Model.Groups)

{

var j = 0;

 

foreach (var user in group.Users)

{

<div class="row">@Html.LookupFor(Model.Groups[i].Users[j].Invitees, additionalData: new[] {  Model.Groups[i].Users[j].Id, Model.Groups[i].Id }</div>

j++;

}

i++;

}

whereat: additionalData[0] maps to userId and additionalData[1] maps to groupId

Cuz in this case there is no necessity for the dictionary. Mappings is done based on the order

Jan 24, 2011 at 8:50 AM

yes, it can be done based on the order but it just doesn't look right, there's no performance costs or anything in putting a dictionary

Feb 8, 2011 at 8:28 AM

it's done, look at the LookupDemo/index.cshtml at the end

Feb 8, 2011 at 11:37 AM

Great to read that!

Btw I saw that in the LookupDemo/index.cshtml you are using dictionary for passing additional parameters (as mentioned above):

@Html.LookupFor(o => o.Characters, data: new Dictionary<string, string> { { "Show", "showId" }, { "Hobbies", "hobbiesIds" } }, multiselect: true, fullscreen: true, title:"drag and drop")

How exactly is done the mapping between Show, Hobbies with the showId, hobbiesIds?

Does the data field have to be always a dictionary or can be some custom or anonymous object?

Is it possible to set a parameters with an explicit value of some anonymous object e.g.

@Html.LookupFor(o => o.Characters, data: new { ShowId = Model.Show, Hobbies = Model.Hobbies }, multiselect: true, fullscreen: true, title:"drag and drop")

Nevertheless, I think you have done a great job. Thank you for your contribution and just keep on rolling with this project!

Feb 8, 2011 at 11:44 AM

thank you

it has to be a dictionary

the reason is that you have to put an alias for an additional data, cuz if you would have a list

@Html.TextBoxFor(o => model[0].HeyId) @Html.Lookup .... data new Dictionary<string,string>{{"[0].HeyId", "Hey"}}

@Html.TextBoxFor(o => model[1].HeyId) @Html.Lookup .... data new Dictionary<string,string>{{"[1].HeyId", "Hey"}}

this way in the LookupController Search Action you will receive a parameter named "Hey", not with different names all the time ([0].HeyId, [1].HeyId)

I'm going to update the documentation