locked
ListView control with fragments as datasource

    Question

  • Hi,

    I am comfortable using a JSON datasource as a ListView control, but I want to take it one step further and use fragments to populate ListView elements. I can load multiple fragments one after another by looping through my fragment list. This generates the output I want, but without all the ListView control goodness.

    How can I combine the two, ListView and fragments? I tried checking the ListView readystate and readystatechange. All I got back was 'loading' for readystate and readystatechange never fired.

    To me it would not seem best practice to load in fragments after the ListView control has been completely rendered. This could cause some odd UI behaviour and cause a 'pause' in the smooth loading of the UI.

    I could not see a way of firing JavaScript from within the "data-win-options" attribute or programatically. Is this easy to achieve? If not, what is the best way of running JavaScript code when creating a ListView control?

    A simple JSON datasource I have is this:

    var fragmentsToLoad = [
    {id: frag1, fragmentSource: '/fragments/frag1.html'},
    {id: frag2, fragmentSource: '/fragments/frag2.html'},
    {id: frag3, fragmentSource: '/fragments/frag3.html'},
    {id: frag4, fragmentSource: '/fragments/frag4.html'},
    {id: frag5, fragmentSource: '/fragments/frag5.html'}
    ]

    From the above JSON datasource, I would like the use ID as the div ID (straightforward enough) and then populate the div in question with the result of a fragment.cloneTo using the 'fragmentSource' data.

    Any pointers or samples would be most welcome.

    Thanks

    Richard
    Wednesday, November 9, 2011 2:50 PM

Answers

  • Hi Richard,

    I think there are two things you can do here.

    1) You can create a ListView that shows a series of iFrames as its content

    2) You can create a ListView with elements that show an image (e.g. a preview of the fragment). You could then use an "iteminvoked" event to load the fragment - use e.srcElement.msDataItem.dataObject to get the item selected and then the fragment you need.

    Have a look at this code that I created to test loading fragments into a ListView:

     

    HTML

     
    <div id="fragmentListViewTemplate"
           data-win-control="WinJS.Binding.Template">
       <div data-win-bind="innerText: id"></div>
       <iframe width="100px"
                        height="100px"
                        data-win-bind="src: source"></iframe>
    </div>
    <div
       id="fragmentListView"
       class="fragmentListView"
       data-win-control="WinJS.UI.ListView"
       data-win-options="{ layout: {type: WinJS.UI.GridLayout},
                                     itemRenderer: fragmentListViewTemplate,
                                     selectionMode: 'none'
                                     }" >
    </div>


    Javascript


    var testFragmentListView = {
        element: undefined,
        control: undefined,
        template: undefined
    }

    function setupFragments() {
            testFragmentListView.element = rootElement.querySelector("#fragmentListView");
            testFragmentListView.control = WinJS.UI.getControl(testFragmentListView.element);
            testFragmentListView.template = rootElement.querySelector("#fragmentListViewTemplate");
            var testData = [
            { id: 1, source: "/htmlFragments/testFragment.html" },
            { id: 2, source: "/htmlFragments/testFragment.html" }
            ];
            var testDataSource = new WinJS.UI.ArrayDataSource(testData);
            testFragmentListView.control.dataSource = testDataSource;
            testFragmentListView.control.itemRenderer = testFragmentListView.template;
            testFragmentListView.control.refresh();
    }

     


     This worked for me in a very quick test to load a series of HTML fragments directly into the ListView. Hope this helped - I'm not sure its exactly what you're looking for. If you're looking to just have images (e.g. as a preview) in the ListView and then cloneTo when a user selects an item, then your Javascript would probably look like this:
    function itemInvoked(e) {
        var selectedItem = e.srcElement.msDataItem.dataObject;
        var fragmentId = selectedItem.id
        var fragmentUrl = selectedItem.source;
        WinJS.UI.Fragments.cloneTo(fragmentUrl, null, targetElement).then(
            function() {
            // Success so do something
           },
            function(error) {
            // Error handling
           });
    }

    Hope this helps.

    David


    David Sanders, MSFT
    • Marked as answer by richlocke Thursday, November 10, 2011 4:28 PM
    Thursday, November 10, 2011 7:48 AM

All replies

  • Hi Richard,

    I think there are two things you can do here.

    1) You can create a ListView that shows a series of iFrames as its content

    2) You can create a ListView with elements that show an image (e.g. a preview of the fragment). You could then use an "iteminvoked" event to load the fragment - use e.srcElement.msDataItem.dataObject to get the item selected and then the fragment you need.

    Have a look at this code that I created to test loading fragments into a ListView:

     

    HTML

     
    <div id="fragmentListViewTemplate"
           data-win-control="WinJS.Binding.Template">
       <div data-win-bind="innerText: id"></div>
       <iframe width="100px"
                        height="100px"
                        data-win-bind="src: source"></iframe>
    </div>
    <div
       id="fragmentListView"
       class="fragmentListView"
       data-win-control="WinJS.UI.ListView"
       data-win-options="{ layout: {type: WinJS.UI.GridLayout},
                                     itemRenderer: fragmentListViewTemplate,
                                     selectionMode: 'none'
                                     }" >
    </div>


    Javascript


    var testFragmentListView = {
        element: undefined,
        control: undefined,
        template: undefined
    }

    function setupFragments() {
            testFragmentListView.element = rootElement.querySelector("#fragmentListView");
            testFragmentListView.control = WinJS.UI.getControl(testFragmentListView.element);
            testFragmentListView.template = rootElement.querySelector("#fragmentListViewTemplate");
            var testData = [
            { id: 1, source: "/htmlFragments/testFragment.html" },
            { id: 2, source: "/htmlFragments/testFragment.html" }
            ];
            var testDataSource = new WinJS.UI.ArrayDataSource(testData);
            testFragmentListView.control.dataSource = testDataSource;
            testFragmentListView.control.itemRenderer = testFragmentListView.template;
            testFragmentListView.control.refresh();
    }

     


     This worked for me in a very quick test to load a series of HTML fragments directly into the ListView. Hope this helped - I'm not sure its exactly what you're looking for. If you're looking to just have images (e.g. as a preview) in the ListView and then cloneTo when a user selects an item, then your Javascript would probably look like this:
    function itemInvoked(e) {
        var selectedItem = e.srcElement.msDataItem.dataObject;
        var fragmentId = selectedItem.id
        var fragmentUrl = selectedItem.source;
        WinJS.UI.Fragments.cloneTo(fragmentUrl, null, targetElement).then(
            function() {
            // Success so do something
           },
            function(error) {
            // Error handling
           });
    }

    Hope this helps.

    David


    David Sanders, MSFT
    • Marked as answer by richlocke Thursday, November 10, 2011 4:28 PM
    Thursday, November 10, 2011 7:48 AM
  • Hi David,

    Thanks for the quick reply.

    I actually had the same thought on the journey home late last night :) I went with the iframe solution and it worked perfectly. This is actually a better solution since I will be including possible content from outside the app.

    The images idea is an interesting one, but not very scaleable especially when it comes to making the app 'world-ready'.

    Thanks.

    Richard

     

    Thursday, November 10, 2011 4:28 PM