Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Using addviews function in jsviews #94

Open
bzuidgeest opened this Issue · 4 comments

2 participants

bzuidgeest Herr Kaste
bzuidgeest

I need some advise using the addviews function in jsviews.

I have the following html

<div class="section rounded span6">

    <div class="section-header single-line">
        <i class="icon-calendar icon-medium icon-single pull-left"></i>
        <h2 class="span2 pull-left">Notities</h2>
        <span class="pull-right"><input id="showAllNotes" type="checkbox" onchange="loadNotes()"/>Toon alle notities van deze student</span>
    </div>

    <div id="divNotes"></div>
    <div class="article-footer">
        <button id="newNote" class="btn btn-primary" >Nieuwe notitie</button>
    </div>

</div>  

Items are retrieved from a webservice and are linked to divNotes using this statement.

$.link.templateNoteRow(data, "#divNotes");

This is the template

<script id="templateNoteRow" type="text/x-jsrender">
    <div class="article no-padding" >
        <div class="article-header" style="height:100%;">
            <p class="inline extra-margin right span2"><i class="icon-calendar"></i>{{toJavascriptDate:Created}}
            <p class="inline extra-margin right span2"><i class="icon-calendar"></i>{{:Category}}</p>

            <button class="btn noteEdit">Bewerken</button>
            <button class="btn btn-danger noteDelete">Verwijderen</button>

            <br />

            <p>{{:~substring(Text, 200)}}...</p>

        </div>
    </div>
</script>

So far so good. Now I want to add another view to this using addviews when a click on the newNote button is clicked. Since I do not like data duplication. I want to use the jsviews addViews function for this directly and not adding items to an observed array. I create my event for the newnote button as below

$('#newNote').on('click', function () {
        if (selectedNoteView != null)
            unselectNote();

        var data = {
            Id: 0,
            StudentId: studentId,
            DossierId: plusDossierId,
            Category: '-',
            Text: '',
            DossierType: 1,
            Created: toMicrosoftDate(Date.now())
        };

 //attempt 1
        $.view(this).views["_2"].addViews($.view(this).views["_2"].views.length, [data], "templateNoteRow");

        //attempt2
        //$.view($(".noteEdit")).parent.addViews($.view($(".noteEdit")).parent.views.length, [data], "templateNoteEditRow");
});

attemp2 can be used as long as the webservice returns at least one item. It finds one item and it use the addviews function on its parent. attemp1 also works when the webservice returned an empty array (which is linked) and there are no items rendered to the screen. However it requires me nowing the index of the view "collection/root". There is more linking going on in the page so in this case it's _2, but that is not very usable and might change.

I tried using $.view($("#divNotes")) but that does not give met the same object as $.view(this).views["_2"].

What is the proper way, if any to get the root view in an reusable way? What statement should I use in $.view(????)

Hope I made the question clear. If not, do say so.

Herr Kaste

Well, looking at your templateNoteRow template I don't see any jsviews syntax used. You could then instead of linking just render:

// $.link.templateNoteRow(data, "#divNotes"); // could be:
$("#divNote").html ( $('#templateNoteRow').render(data) );

Now when you add a note you could just render the new data in your click-handler, but instead of replacing the html of the #divNotes append it.

$("#divNote").append ( $('#templateNoteRow').render(new_data) );
bzuidgeest

Thank you for your response. It is true that this template does not contain any data-linking making your point on that valid. However that was me not thinking and keeping the question short (-ish).

The actual new note template looks more like this

<script id="templateNoteEditRow" type="text/x-jsrender">
    <div class="article no-padding" >
        <div class="article-header" style="height:100%;">
            <p class="inline extra-margin right span2"><i class="icon-calendar"></i>{{toJavascriptDate:Created}}</p>
            <p class="inline extra-margin right span2">
                <select data-link="Category" class="searchable">
                    <option value="-">-</option>
                   @foreach(var category in ViewBag.NotesCategories)
                    {
                        @:<option value="@category">@category</option>
                    } 
                </select>
            </p>

            <br />

            <textarea class="inline extra-margin right" style="width:920px;height:200px;" data-link="Text" ></textarea>
            <button class="btn noteSave">Opslaan</button>
            <button class="btn btn-danger noteCancel">Annuleren</button>
        </div>
    </div>
</script>

As you can see it does use data-linking. There is also some mvc razor code in their to render out a dynamic but within the page fixed set of select options. I thought that would make it less suitable as an example.

At the moment I use the code below to find the element I need, but I was hoping something prettier was possible. Although giving that I rarely have more than three linked area's on a page it's performance is more than adequete.

$.each($.view(this).views, function (i, n) {
            if (n.parentElem == $("div#divNotes")[0])
                root = i
        });

        $.view(this).views[root].addViews($.view(this).views[root].views.length, [data], "templateNoteEditRow");
Herr Kaste

I don't think I would go this way, because atm it seems like using internal apis that will change. But it already is short code, so that's a win.

I still think that I would use a {{for Notes}} loop to render the notes.

<div id="divNotes">{{for Notes tmpl=... /}}</div>

If you just use addViews your rendered html doesn't match your underlying data, does it? Now I probably wouldn't insert a new note in the $('#newNote').on('click' ...) handler either because the user still can save or cancel. I would add it to a staging area.

<div id="divNotes">
   {{for Notes tmpl=... /}}
   {{for NewNotes tmpl=templateNoteEditRow /}}
</div>

If the user clicks the save button move the new_note from NewNotes to Notes.

data = { Notes: [...], NewNote: null }

$newNote.onClick => $.observable(data).setProperty('NewNote', data);

$save.onClick => $.observable(data.Notes).insert(0, data.NewNote) && $.observable(data).setProperty('NewNote', null)
$cancel.onClick => $.observable(data).setProperty('NewNote', null)

So to speak, I would try to dance with the data as long as possible.

bzuidgeest

I considered the internal api issue. It's just that the gamble seems worth it.

I really dislike using extra variables to store the data from the server when that data is available in the dom thanks to jsviews. This also goes for keeping track of which items are "selected". Info like that should be gathered from jsviews/dom, not stored in variables. Makes multiselect and such really easy.

I do not completely understand what you mean by this: "If you just use addViews your rendered html doesn't match your underlying data" When I add a view it is accompanied by a new data item. The new data item has an id of zero. On the submitting of the note the ajax web service considers items with a zero id as new and add's it to the sql store. If the user never submits or cancels it it will have never existed. I do not see any inconsistencies in that.I could even store it on the server on creation and add the view after that, but that would need an delete request on a cancel and that would just be a waste. I also make my webservices return different statuscodes and use the statuscode property of the jquery ajax call to respond to those. I even return the complete object on succesfull save, which is rendered in the non-edit template so the user always sees what is stored and I have the notes new id.

In another issue of mine boris commented on, he said he hopes to have a new version in few days. Let's see what happens :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.