Enhancing your LightSwitch List, Tiles and Table controls – Updated!
We have refactored from the earlier build… so please review the new steps!
As of May 2014, Out of the Box LightSwitch list, tiles and table controls only allow for selection of a single item.
Until now!
The demo/test drive has been updated showing the new upcoming functionality check it out: MultiSelect Preview
So… we’re like squirrels here, constantly distracted. And so with that said, we’ve nailed down our long term name for the library. Going forward we’ll be branding as LightSwitch Wires, or lsWires for short. Since in reality that’s kind of what we all do. We add the wiring to LightSwitch to make things work or work better. And this naming convention works for our other disciplines like Kendo UI and Syncfusion. We’ll keep the “Wires” branding and just swap out the prefix for the type of wires we’re providing. Thanks for your patience, this is the LAST breaking change.
Now on with it… Within the lsWires library we've provided the functionality to enhance the list and table controls
- Selection of multiple items
- Ability to limit the number of selections
- Select/Unselect all items
- Get the selected item count
- Retrieve the data of the selected items
- Persist selections for the session
- We no longer take over the ItemTap
- Multiple lists can be on the same screen
- Same code base works across all 3 control types
Sounds awesome eh? So lets get started on how to implement this new functionality…
- Create a new LightSwitch 2013 HTML Application
- Lets name it: itgLsMultiSelect
- When at the Start with data screen, click on Attach to external…
- Data Source Type: OData Service
- OData service endpoint:
http://services.odata.org/northwind/northwind.svc/ - Authentication type: None
- Choose the following entities:
Customer
Employee
Product - Name the data source: Northwind
- Click the finish button
- Close any open editor windows
- Save your solution
- Over in your your Solution Explorer pain
- Add the following NuGet package to the HTML Client project
lo-dash.js - From our GitHub repository
Add lsWires.js to your Scripts folder
Add lsWires.css to your Content folder - Now open up your default.htm file in the client project
- Add lo-dash.js followed by lsWires.js to the scripts section
- Add the lsWires.css as the last stylesheet
- Right click on the Screens folder, select Add Screen…
- Select Browse Data Screen
- Screen Data: Northwind.Customers
- Click ok
- Save your solution, run the application
- Go ahead and click on items, notice single selection
- Stop your application
- Click on the Tile List, Customers
- Click on Edit PostRender Code in the properties window
- To get intellisense, drag from solution explorer the file lsWires.js onto your page
- Now we only need ONE line of code to enable multi-select
// Enable multi-item selection on this tile control lsWire.list.enableMultiSelect(contentItem);
- Before you can run, remove the default ItemTap that LightSwitch automatically adds for the list. We did not create the view screen that the ItemTap is expecting so you’ll get an error when selecting if you don’t.
- Save your solution, run your app
- BOOM! Multi-Select enabled!
- You can also unselect by clicking a selected item
- Hmmmm… how do I get the data of the selected items?
- Stop your application
- Under the Customer List Tab, add a new Group
- Move it right under the Command Bar
- Change the type to be a Columns Layout
- Then add 3 more Rows Layout under the columns layout
- For all 3 change the width setting to Fit to Content
- Add a new Button into the first rows layout
- Select Write my own method, name it: GetSelected
- Double click the button to edit the code
- We're going to add a few lines
Get the list contentItem
Call our method to get the data, which returns an array of entities
Then we'll display the datavar list = screen.findContentItem("Customers"); var count = lsWire.list.selectedCount(list); var selected = lsWire.list.selected(list); var text = "Customers Selected\n\n"; _.forEach(selected, function(item) { text += item.CustomerID + " - " + item.CompanyName + "\n"; }); text += "\n\nCount = " + count; window.alert(text);
- Save and run your application
- Select a few items, click on Get Selected
- Unselect a few, Get Selected, only selected get returned
- Ok lets continue going thru adding functionality
- Add two local properties, boolean
- Name them SelectAll and SetLimits
- Drag the SelectAll under the second Rows Layout
- Change the control type to be of a Custom Control
- Over in the properties window, set the label position to None
- Then click on Edit Render Code and add the following
// Render a checkbox lsWire.checkbox.render(element, contentItem); // When the checkbox changes state, either select all or not contentItem.dataBind("screen.SelectAll", function (newValue) { if (newValue != undefined) { var list = contentItem.screen.findContentItem("Customers"); lsWire.list.selectAll(list, newValue); } });
- Now drag the SetLimits property under your 3rd Rows Layout
- Change the control type to be of a Custom Control
- Change its Display Name to: Limit of 4
- Change the label position to None
- Then click on Edit Render Code and add the following for this one, its a bit more lengthy as we’re adding in some cool features
// Render our checkbox lsWire.checkbox.render(element, contentItem); // When the checkbox changes state, set or remove our limits contentItem.dataBind("screen.SetLimits", function (newValue) { if (newValue !== undefined) { // Our dependent item var selectAll = contentItem.screen.findContentItem("SelectAll"); // Get our list var list = contentItem.screen.findContentItem("Customers"); // Current count of selected items var count = lsWire.list.selectedCount(list); // If the checkbox is selected, limit to 4 items if (newValue != undefined && newValue === true) { // Set our limit, returns the limit count var ttl = lsWire.list.totalSelectionsAllowed(list, 4); // if select all was set, checked if (selectAll.value === true) // set the property to false, dataBinding will do the rest contentItem.screen.SelectAll = false; // Else is the current count greater than our limit? else if (count > ttl) { // Count is greater, so unselect all items lsWire.list.selectAll(list, false); } // Since we are limiting, disable the select all checkbox selectAll.isEnabled = false; } else { // Limit was unselected, renable select all and remove limits selectAll.isEnabled = true; lsWire.list.totalSelectionsAllowed(list, null); } } });
- Its that easy!
- Save and run your application
- Toggle your limits
- Select your 4 items, try and select a 5th
- No can do! Now unselect a selected and select another
- Notice the Select All is no longer a valid option
- Uncheck the Limit of 4
- Test again, notice the limitations were removed
- So what happens if this was a list vs a Tile List?
- Stop your application
- In the screen designer, change the control type to List
- Run your app, test the functionality
- As you see, same code, different control type, same results!
- Now you ask… table too?
- Yep! Go ahead and change it to a table control
- Run and test the app
- Same code, works as expected on all 3 controls!
So there you go… an easy, reproduceable method of enabling multi-select on your LightSwitch list controls. You can even have multiple lists on the same screen, each will behave independently. We'll leave that up to you to go play around and test. Our sample project already has a multi-list screen if you want to go check it out.
We’ve added functionality to persist selections for a session. Its also a key part for a table control if you are going to allow your clients to change the sort order by clicking on the columns. You’ll set the control to persistSelections and it won’t be a problem. Check out the sample project for the code, its quite simple. Also check out the live preview on how it works.
Obviously if you are using an ItemTap to get to an edit/view screen, you would not implement this, but you could, since we no longer take that over and we do allow for persistent selections. But for most, selection and batch processing, this is the ticket.
One final note regarding the Select All functionality. We are selecting and working with rendered items. So with virtual scrolling, not all items from a query have been returned and rendered. Which means if you do a Select All, scroll and more data comes down, the new data is not selected. Of course one could go and press the Select All button again, or you could do a dataBind and fire off another Select All. But I don't see many instances of where that is appropriate. But you could.
Enjoy! More to come…
Works perfectly. Thanks for this, it took me a while to find something this helpful.
I’m new at using Lightswitch so I will really appreciate your help if you could please tell me how I can insert the same data for each selected item?
How to fix :
CustomControl error: Details_postRender() method error: TypeError: Cannot read property ‘details’ of undefined
Great work thanks. Working well except selection is not kept when the column header is clicked to sort?
I don’t see many comments here, it means you have not many visitors. I know how to make your page go viral. If you want to know just search in google for:
Kimting’s Method To Go Viral
I get this error Customcontroerror:Conditons_PostRender()Method error:TypeError: Cannot read property enableMultiSelect of undefined
I have a list where I would like the user select more than one option
Hi
Thanks for blog
I can’t find lodash.js by Nuget, where else can I find
Thanks
Its a pretty popular library. If you can’t find it on nuget, just go to http://www.lodash.com
Thanks
Hello can anyone tell me how to enable a button event ? i have create a button in each row but the event is not fired ? only with onclick … but then it does not work on mobile … 😦
thank you
Hi
Please help.
In my application i used the enableListToBeMultiSelect of the new lsWire.js file and it’s working fine in desktop browsers but i try’d it on an android phone and it’s dose not work.
Do you know why and how i can solve this?
Thanks
I am trying to take a source collection and “select” the ones in the target collection (my lswires list) but am having a problem accessing the “selected” property of the lswires list? In other words, I have a list of chosen items that I want to have pre-selected in the lswires collection by iterating through the chosen items collection and having them “selected” in the lswires list collection?
Here is some of my code:
myapp.OrganizerAddEditRaceEvent.EventTypes_postRender = function (element, contentItem) {
lsWire.list.enableMultiSelect(contentItem);// Enable multi-item selection on this tile control
var list = contentItem.screen.findContentItem(“EventTypes”);
contentItem.screen.getRaceEventFeeOptionsCollection().then(function (REFO) {
REFO.refresh().then(function () {
contentItem.screen.RaceEventFeeOptionsCollection.data.forEach(function (refo) {
_.forEach(list.value.data, function (item) {
if (item.Name == refo.EventType.Name) {
lsWire.list.item.selected = true;
}
});
});
});
});
};
everything works down to the “lsWire.list.item.selected = true;” statement which does not “select” the item?
I Hope that makes sense?
Scott
Scott,
lsWire does not have the list object which is why its failing. if I’m hearing you correctly, you are wanting to preselect a set of list items based on an array of items. If so, there is a helper function within lsWires. Take a look at:
selectListItems: function (contentItem, arrayOfIds, yesNo)
which would translate to:
lsWire.selectListItems(yourListContentItem, yourArrayOfIds);
Let me know if that works for you or not.
dale
Hi
Is there a way to “unselect” all list items?
Thanks
Yes… you pass a Boolean as the second parameter to selectAllListItems
Sent from Surface
Hi
I try’d lsWire.list.enableMultiSelect(contentItem); but i’m getting an exception “JavaScript runtime error: Unable to get property ‘enableMultiSelect’ of undefined or null reference”,
So i searched in my IsWire.js file but didn’t find window.list instead i found “enableListToBeMultiSelect” function try’d that
myapp.AddSteadyWaiter.Waiters_postRender = function (element, contentItem) {
// Enable multi-item selection on this tile control
setTimeout(function () {
lsWire.enableListToBeMultiSelect(contentItem, 6);
}, 1000);
};
but getting exception that totalAllowedSelections is undefined?
Please help Thanks.
There is a bug in the enableListToBeMultiSelect function… the latest js file can be downloaded here… http://lightswitch.codewriting.tips/uploads/lswires.zip This should take care of your problem.
Thanks it works perfect.
if I want to implement the itemTap how should I do that?
i vote on this one to ! 🙂 im struggling with tis one 😦
I’m not clear on what you mean… I’ll post later today how I use multi-item selection in a pick list. Sorry its been confusing.
its working perfectly dwm9100b 🙂 … the problem is you cannot acess the tap event to go to details screen … get it ? … it selects the row but it not performs the tap event on the button
thank you
I see.. yep that’s one of the downsides of a multi selection list. Work around is to put a link or button in each list item that will go to its particular details. Easily done also.
yes i already did that …the problem is that im calling the link directly to open a edit screen …
as im using a ria service from a stored procedure on my multiselect grid and dont know how to open a edit screen with a specific entity id … im using this
window.location.href = “/HTMLClient/#/AddEditContract/” + contentItem.value + “/[d27c58251]”;
but it does not work very well 😦 and i bet its not the best solution
do you know any alternative to open a screen with a specific entity to edit ?
thank you
AS
Ya that will cause issues due to the static screen ID. That ID is used for tracking internally by the LS navigation stack. Best practice is to create a screen parameter and pass the entity.
do you know how can i do that ?
thank you
Check out the tutorial I just posted. We show how to pass an entity in there. If that is still confusing, I’ll put something together for you.
I am a bit confused by this. In this same page you say “•We no longer take over the ItemTap”.
What I would like to do is make a kind of shopping cart. On tab 1 I want to multi-select a few items. On tab 2 I want to create a bulk-edit of the multi-selected items. Every time I (de)select an item on tab 1 I want to update the displayname of tab 2 to show “there are now (N) items in your cart”. For this I need the itemtap but code in that handler is never reached (not even a hit on a breakpoint)
Hi thanks for this post it’s grate.
just one thing if I want to implement the itemS how should I do that?
Thanks
Sorry itemTap
Hi Dale, Great Job! and it works fantastic but I have a situation, when I use post render on List Items to mark them disabled if they already added enabling Multi Select still allows selecting disabled items. Any idea how I can make it to not to select if List items are marked contentItem.isEnabled = false
I am using a table grid. When I add a button in each row to call a dialog window: The multi-select is blocking the button click event. If I comment out the multi-select line “lsWire.list.enableMultiSelect(contentItem);” the event of the button works well. Any ideas on how to solve tis problem. Thanks in advance.
Hi Dale, awesome as usual!
I’m one of those people that wants it all 🙂
I’m trying to incorporate some of the stuff mentioned in the post above into a screen designed with your also excellent ‘Enhanced Grid’ template; for example, enabling multiselect, which appears not to be incorporated in that project.
Picking up your list/table etc post-render code (for the enhanced grid/table):
contentItem.enhancedTable = new itgLs.EnhancedTable({
element: element,
contentItem: contentItem
});
I’ve tried various combinations/positions of this line of code as in the post above within this stub:
lsWire.list.enableMultiSelect(contentItem);
or even:
lsWire.list.enableMultiSelect(contentItem.enhancedTable)
To no avail! Code breaks in lswire.js line 415:
contentItem.screen[contentItem.name].selectedItem = itemData
with a null reference.
Any ideas please?
Is it even possible to ‘mix-up’ the two projects’ features?
I had the same issue. I tracked it down to the fact that I had more than one screen instance of a collection (e.g. my collection is “Options” and my screen controls were “Options” and “Options1”)(by default, LS adds a “1” to the next instance of the control. I determined that the screen control “Name” must match the collection and it works. It would not work on the second “Options1” control at all. I always got the same error. The error “sort of” gives an indication like that since it’s looking for “contentItem.name”.
Hope this helps!
Scott
hi
There are questions
Unzip the file, run the example, the error is emanating
What is the problem?
And you can not, depending on the starting 29
Are not multiple-choice.
A warning that the package is useless out
Do you know why?
I’m not understanding your comments, I’ll email directly to see what the issues are.
Awsome post, Is it possible to put the select All button on command bar ???
Absolutely, its just a function call, so create a new button, write your own method and then call the selectAll method.
I have used your grid control but in couple of projects. I am trying to figure out how to add paging using WCF RIA. Any ideas
I’ve not worked with the WCF RIA sources so I’m not much help in that area. If I get a chance I’ll give it a shot. my apologies.
awesome demo…i would love to know how to implement the functionality for the tilting help menu… 🙂
thanks!
Thanks Isaac… Took a while to get that tilting working with LightSwitch, but the possibilities are cool when it comes to help or menus. I’ll try to put up a post on how to accomplish this if there is interest.
Still loving the multi select!!!! Sure hoping someone else shows intrest in the help menu…sure would like to see a tutorial! 😉
Great article, thank you for sharing this with us,
But there is one issue I’m stuck with maybe some of you have seen it before.
in the lswires.js file like 444
$.each(selected, function (item) {
// Get our data out of the jQuery cache
var entity = $.cache[item[$.expando]].data.__entity;
if (entity !== undefined)
data.push(entity);
});
$.cache[item[$.expando]] – element is always undefined !!!
but the “selected” variable contains the list of td elements that I have selected on the table.
Can you please advice, what I’m doing wrong.
I’ll email you directly to help work the issue out.
What was the advice, on this one?
I have a similar problem in itemTap()
var itemData = $.cache[item[$.expando]].data.__entity;
Gives the error:
JavaScript runtime error: Unable to get property ‘undefined’ of undefined or null reference
I can’t get the multi-select to work at all.
(Windows 10 / VisualStudio 2015 / IE 11.0.14393 / .Net 4.6)
Hi i hace similar problema, and have identical pc configuration
[…] LightSwitch 2013 HTML Client – Easily add Multi Item Selection to your Lists and Tables! […]
i really liked your post but have some awkward kind of issue at my end, when i publish the light switch application in release mode the alert scripts and script below it seems to not work.
Any suggestion on what am i doing wrong.
thanks
Hi,
I get an error when trying to select:
contentItem.screen[contentItem.name].selectedItem = itemData;
The reference is null or undefined.
Followed your instructions.
By the way, I cannot find lo-dasg.js, only lodash.js. The same?
Regards
Sven
Hmmm… I don’t see in the posting lo-dasg.js… I’m checking again the instructions. Did you download the sample project and get that to run successfully?
Hi
I meant lo-dash.js
Sven
Yes. Your project works great, nut not mine 😦
Hi,
The selectAll works though, but not when I click on one line.
Sven
Hi again,
This is strange. I removed all: contentItem.screen[contentItem.name].selectedItem = xxx. in your .Js
Now it all works. Know why?
I forgot. Great work with this one, It’s super nice.
Sven
Hi,
the render worked but obviously it did not trigger “selectedItem”
It was fun for a while 🙂
Sven
Re the error… are you able to zip up your project and send it over? I’m not able to repro…
Hi,
The project is so big and have multiply connections
I will have to leave this for now.
Maby the complexity of my project messes things up.
Sven
One thing I left out… which I’ll add into the instructions is this… LightSwitch adds a default ItemTap for the list, but we never added the screen. So delete the ItemTap in properties.
in the “Browse Employees and Products” view on the live test drive site, the Product list view works fine. But, if you change the sort by selecting a column header, the multi-select no longer works.
Interesting… I will investigate and see what I can fix. Thanks for the catch!
This has been fixed, live preview has been updated and along with gitHub repositories. Thanks for finding this bug!
[…] https://blog.ofanitguy.com/2014/05/07/lightswitch-2013-html-client-easily-add-multi-item-selection-to… […]
Article very didactic, easy to implement and very powerful!
Very creative Dale. Thanks a lot.
Great work but FYI, using your ‘MultiSelect Preview’, there appears to be a bug. Using Desktop IE11, First entry ‘Select All’ doesn’t select the last customer but if you ‘Unselect All’ then ‘Select All’ it works OK. Worse on Android (Nexus 7) because as you scroll down the bottom block of customers do not show as selected i.e. are not pale Blue. Unselecting all then selecting all again does not seem to fix the problem.
I haven’t had time to read the details of your blog yet so if there’s some reason you don’t select all when the button is pressed then it’s not a bug but a feature (as we say). Anyway, as a users, it wasn’t what I expected. BTW My quick test showed that ‘Limit’ code seemed to work well.
Hey thanks for the comments. LightSwitch works based on virtual scrolling. The selectAll will only select what has been loaded into the DOM at the time selectAll is pressed. LightSwitch by default loads 45 at a time. Once you start scrolling down it keeps loading more. Which means you will see unselected items if its a large list. Which in reality you probably wouldnt be selectingAll. I talk about this at the bottom of the Blog post. Perhaps I’ll force the loading of all the items in the preview.
Yeah I thought you might have a reason and I could see that it was not selecting beyond the data refresh and that’s kind of random maybe based on whether the customer tiles display 1-up, 2-up, 2-up etc. i.e. the form- factor or the browser and the amount of scrolling involved. Because it was inconsistent depending on the two browser / form-factors I chose I would prefer that it actually did select ALL customers. I might want to assume that, without scrolling, that everything had been chosen regardless of the technical vagaries of the development tools defaults. i.e. ‘Dumb User’ POV.
So to that extent I would support a full load as the default in this case or a more complicated page by page selection option i.e. only what I can see is selected when I say ‘Select All’ IOW ‘Select All Visible Customers’.
Not sure to what extent loading all customers would slow down the load though. You certainly wouldn’t try that with a million customers in the DB.
I can see a use for this in user config e.g. which States are you following, the users selects them and you save the data to a config to default for next time. Plenty of other uses too. I very much appreciate you work.
Cheers. Working as I would expect now. Consistent on Droid, IE11 DT & iOS. Impressively instant selection on my iPhone4 BTW. I look forward to getting the time to dive into your blog and figure out what you’ve done to achieve this result.