Giter Club home page Giter Club logo

jsviews's Introduction

JsViews: next-generation MVVM and MVP framework - bringing templates to life

CDNJS version

The power of MVVM, the flexibility of JavaScript, the speed and ease of JsRender templates and jQuery

JsViews builds on top of JsRender templates, and adds data-binding and observable data, to provide a fully-fledged MVVM platform for easily creating interactive data-driven single-page apps and websites.

Documentation and downloads

Documentation, downloads, samples and API docs and tutorials are available on the www.jsviews.com website.

The content of this ReadMe is available also as a JsViews Quickstart.

JsViews installation

jsviews.js is available from downloads on the jsviews.com site.

CDN delivery is available from the cdnjs CDN at cdnjs.com/libraries/jsviews.

Alternatively:

(Note that jsviews.js includes all of jsrender.js code -- so jsrender.js does not need to be loaded first.)

JsRender and JsViews

JsRender is used for data-driven rendering of templates to strings, ready for insertion in the DOM. (See JsRender Quickstart and JsRender GitHub repository).

JsViews incorporates JsRender templates, together with data-binding, observable data and MVVM support. It provides a powerful platform for building dynamic interactive websites and single-page apps.

(Note: JsRender and JsViews together provide the next-generation implementation of the official jQuery plugins JQuery Templates, and JQuery Data Link -- and supersede those libraries.)

JsViews usage

Data-linked templates

JsViews provides data-linking - so that JsRender templates become data-bound:

  • Data-linked tags or elements in your templates will update automatically whenever the underlying data changes.
  • Some data-linked tags or elements provide two-way data-linking, so that user interactions will trigger "observable" changes to the underlying data (which may then trigger other updates elsewhere in your templated UI).

Data-linked template tags:

Any JsRender tag, {{...}} can be data-linked by writing {^{...}}, as in:

<ul>
  {^{for people}} <!--List will update when people array changes-->
    <li>{^{:name}}</li> <!--Will update when name property changes-->
  {{/for}}
</ul>

Learn more...

Data-linked HTML elements:

HTML elements within templates can be data-linked by adding a data-link attribute:

<input data-link="name"/> <!--Two-way data-binding to the name property-->
<span data-link="name"></span> <!--Will update when name property changes-->

HTML elements within 'top-level' page content can also be data-linked -- see below.

Learn more...

Render and link a template

With JsRender, you call the render() method, then insert the resulting HTML in the DOM.

var html = tmpl.render(data, helpersOrContext);
$("#container").html(html);

With JsViews, you can instead call the link() method:

tmpl.link("#container", data, helpersOrContext);

which in one line of code will:

  • render the template
  • insert the resulting HTML as content under the HTML container element
  • data-link that content to the underlying data

Now observable changes in the data will automatically trigger updates in the rendered UI.

There are two ways of calling the link() method:

Example: - Template from string

var tmpl = $.templates("{^{:name}} <input data-link='name' />");
var person = {name: "Jim"};
tmpl.link("#container", person);

Example: - Template from script block

<script id="myTemplate" type="text/x-jsrender">
{^{:name}} <input data-link="name" />
</script>
var tmpl = $.templates("#myTemplate");
var person= {name: "Jim"};
tmpl.link("#container", person);

Example: - Named template from string

$.templates("myTmpl1", "{^{:name}} <input data-link='name' />");
var person= {name: "Jim"};
$.link.myTmpl1("#container", person);

Example: - Named template from script block

<script id="myTemplate" type="text/x-jsrender">
{^{:name}} <input data-link="name" />
</script>
$.templates("myTmpl2", "#myTemplate");
var data = {name: "Jim"};
$.link.myTmpl2("#container", data);

Result: After each link() example above the container element will have the following content:

Jim <input value="Jim" />

with the name property of person object data-linked to the "Jim" text node and two-way data-linked to the <input />

See: Playing with JsViews for working samples, such as this one

Learn more...

You can use data-linking not only for templated content, but also to data-bind to top-level HTML content in your page:

$.link(true, "#target", data);

This will activate any declarative data-binding (data-link="..." expressions) on the target element - or on elements within its content.

Learn more...

Making "observable" changes to objects and arrays

In current JavaScript implementations, modifying objects or arrays does not raise any event, so there is no way for the change to be detected elsewhere. JsViews dynamic data-bound UI solves this through data-linking, using the JsObservable observer pattern.

The JsViews $.observable() API provides a way for you to change objects or arrays observably. Each change will raise a property change or array change event.

Modify an object observably

$.observable(person).setProperty("name", newName);

$.observable(person) makes the person object "observable", by providing a setProperty(...) method. Use setProperty to change a value, and the change will be "observed" by the declarative data-binding in the template.

Modify an array observably

$.observable(people).insert(newPerson);

$.observable(people) makes the people array "observable", by providing methods like insert(...) and remove(...). Use them to make changes to arrays, and the changes will be "observed" by data-bound elements and tags in the template - such as the {^{for dataArray}} tag.

Learn more...

Responding to data changes

JsViews uses the property change or array change events to make any data-linked tags or elements in your templates update automatically in response to each observable change in your underlying data. In addition, with two-way data-linking, it ensures that those events are raised when the user interacts with a data-linked template, and causes changes to the underlying data.

observe() and observeAll()

The $.observe() and $.observable().observeAll() APIs make it very easy for you to register event handlers or listeners, so your code can listen to specific observable changes made to your data objects or view models:

$.observe(person, "name", function(...) {
  // The "name" property of person has changed
  ...
});
$.observable(person).observeAll(function(...) {
  // A property of person, or a nested object property, has changed
  ...
});

Learn more...

Accessing the view hierarchy

Each instance of a rendered template or a template block tag is associated with a JsViews "view" object -- so nested tags lead to a hierarchy of view objects. The view hierarchy shows how the underlying data objects map to the rendered UI.

From UI back to data:

Use $.view(elem) to get from a DOM element to the corresponding view object for that part of the rendered content. From the view you can then get to the underlying data, the index, etc.

Example:

{^{for people}}
  ...
  <button class="changeBtn">Change</button>
  ...
{{/for}}

Click-handler code for Change button:

$(".changeBtn").on("click", function() {
  // From the clicked HTML element ('this'), get the view object
  var view = $.view(this);

  // Get the 'person' data object for clicked button
  var person = view.data;

  // Get index of this 'item view'. (Equals index of person in people array)
  var index = view.index;

  // Change the person.name
  $.observable(person).setProperty("name", person.name + " " + index);
});

Learn more...

Data-linked paths

JsViews data-linked templates (and the $.observe() API) use the same paths and expressions as JsRender templates, but in addition provide 'leaf' data-binding -- such as:

{^{:team.manager.name`}}                    <!--updates when name changes-->
<span data-link="team.manager.name"></span> <!--updates when name changes-->
<input data-link="team.manager.name" />     <!--two-way binding to name-->

But data-linked paths have additional support, such as linking deeper into paths:

{^{:team^manager.name}}   <!--updates when name, manager, or team changes-->

Learn more...

Computed observables

JsViews also allows you to data-bind to computed values, such as:

{^{:shoppingCart.totalAmount()}}        <!--updates when totalAmount() changes-->
<input data-link="person.fullName()" /> <!--two-way binding, computed fullName()-->

Learn more...

Documentation and APIs

See the www.jsviews.com site, including the JsViews Quickstart, JsViews APIs and JsObservable APIs topics.

Demos

Demos and samples can be found at www.jsviews.com/#samples, and throughout the API documentation.

(See also the demos folder of the GitHub repository - available here as live samples).

jsviews's People

Contributors

borismoore avatar gulping avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jsviews's Issues

Support data-link binding back to a simple array of strings

JsViews seems to work fine when binding data from a simple array with #data (which basically is a short cut to access the data attribute directly.) However, this doesn't work when the array item has been updated in an input, since jsviews try to trigger setProperty on a simple property. Results in changes not reflected to the original array.

Update rendered content of #if-else without re-rendering the template itself

If I have an {{#if}}... {{else}} ... {{/if}} block in a template and somewhere in the javascript code I make a "setProperty" method call on a data property that my {{#if}}/{{else}} code uses for rendering some texts, then I have to call the render() method on the view so that the {{#if}}/{{else}} block is evaluated again with the new data property value (because the template itself is rendered again).

Here is my sample code:

<script id="myTemplate" type="text/x-jquery-tmpl">
    <tr>
        <td data-getfrom="[Age]"></td> @This td will be updated without calling "render()" on the view.@
        <td> @But this td will not be updated without calling "render()" on the view:@
            {{#if Age > 25}}
                Greater!
            {{else}}
                Not greater!
            {{/if}}
        </td>
        <td><input type="button" id="btnSetAgeProperty" value="Set age property"/></td>
    </tr>
</script>

<table>
    <tbody>
        <tr>
            <th>Age</th>
            <th>Is greater than 25?</th>
            <th>Set age property</th>
        </tr>
    </tbody>
    <tbody id="myList">
    </tbody>
</table>

<script type="text/javascript">
    var ages = [{ Age: 5 }];
    var myTemplate = $("#myTemplate").template();
    $("#myList").link(ages, myTemplate)
    .delegate("#btnSetAgeProperty", "click", function () {
        $.observable($.view(this).data).setProperty("Age", 30);
        $.view(this).render(); // This needs to be called for the "Greater"/"Not greater" text to be updated!
    });
</script>

Is it possible that the content of the {{#if}}/{{else}} block (the "Greater"/"Not greater" text) is refreshed without calling the
$.view(this).render() anyway?

get view by data

Is it possible to get View-objects by data? For example: If i create 3 views linked to the variable data, is it possible to find the 3 views with the observable $.observable(data)?

Support for textarea

Hi,

I'd like to add support for link to textarea elements. Could you give some hints about ?

Underlying data updated only at loseFocus

Dear All,

I have the following template:

<script id="rrTemplate" type="text/x-jquery-tmpl">
    <p>
        <span>Number of full rounds:</span>
        <input data-getfrom="[NumOfFullRounds]" data-to="[NumOfFullRounds]" class="numericValue"/>
    </p>
    <p>
        Reps in partial round:
    </p>

    {{#each RepetitionItems}}
        <div>
            <span><input id="txtRep{{=Id}}" data-getfrom="[Value]" data-to="[Value]" class="numericValue XXX"/></span>          
            <span data-getfrom="[Value]"></span>
        </div>
    {{/each}}
</script>

The problem is, that in the each-block, if the user types anything into the input-field (textbox), the span next to it (which is bound to the same property) is updated only when the textbox loses focus. How to make it possible to updated on-the-fly?

Thanks!

Allow ctx-helpers in the data-to field

something like this

<input data-getfrom='$ctx.to_ui([sample])' data-to='$ctx.from_ui([sample])' />

Say, the user enters '2.5' or '2,5' meaning two and half hours, but we store minutes etc.

Node is undefined

Im encountering an issue where "node is undefined".
After stepping through the code I found this occurs after the "createNestedViews" function has run through all of my elements.

node is undefined
node = node.nextSibling;

Any suggestions / known issues to what may be causing this?

I am using Tags, Helpers & nested templates.
Can post some code if required.

How to create jQuery UI stuff in templates?

Dear All,

I like the templating thing, but I want to create a little bit more complex UI, eg. using jQuery sliders in the templates or using min-max values for textboxes (via jstepper) etc.

All these things require javascript/jquery code to be executed.

My problem is that neither via Helpers nor via delegates I can't achieve this.

My example code is (SORRY, I don't know why does gitHub screw the formatting!):

<div id="rr" style="background-color: Lime">    
</div>

<script id="rrTemplate" type="text/x-jquery-tmpl">
    <p>
        <span>Number of full rounds:</span>
        <input data-getfrom="[NumOfFullRounds]" data-to="[NumOfFullRounds]" class="numericValue"/>
    </p>
    <p>
        Reps in partial round:
    </p>

    {{#each RepetitionItems}}
        <div>
            <span><input id="txtRep{{=Id}}" data-getfrom="[Value]" data-to="[Value]" class="numericValue XXX"/></span>
            {{=$ctx.setMinAndMaxValue("#txtRep" + Id, 0, Max)}}
            <span data-getfrom="[Value]"></span>
        </div>
    {{/each}}
</script>

<script type="text/javascript"> 

    $.views.registerHelpers({
        setMinAndMaxValue: function(selector, minVal, maxVal){
            alert("setMinAndMaxValue called, but jQuery selector will not work :( ");

            $(selector).click(function(){alert("jQuery worked in the template!");}); //the jQuery selector will find nothing
            $(selector).jStepper({minValue:minVal, maxValue:maxVal}); //the jQuery selector will find nothing
            return "";
        },      
    });


    $(document).ready(function () {

             var regVM = {"NumOfFullRounds":5,"RepetitionItems":[{"Max":2,"Value":0,"Id":"A1"},{"Max":4,"Value":0,"Id":"A2"},{"Max":6,"Value":0,"Id":"A3"}]};

        var templi = $("#rrTemplate").template();
        $("#rr").link(regVM, templi)
            .on("load", ".XXX", function(s)
            {
                alert("textbox loaded!"); //this line never executed
                $(selector).jStepper({minValue:minVal, maxValue:maxVal}); //so this line can't attach anything also :(
            });
    });
</script>

When the setMinAndMax values are executed, jQuery can't find the elements defined in the selector.

Via the "on" I can't make it work to fire when the textboxes are displayed (via the templates).

I know that helpers are for generating output, but I think it would be much better to hold the template and jquery ui-displaying code in one place, than separated all over.

I'd appreciate any replies.

Thanks!

More a practice question than an issue

That's not a issue, but i can't find a place to ask (maybe an IRC channel, forum, or else ?)

I used first jsRender to create a simple uploader UI widget.

The goal is to get the same features as the Google+ upload widget.
Especially this feature :

1/ When a file is added for upload, an element with a progress bar is appended
2/ When a file upload is done, the current element is replaced by another one, the final uploaded file (2 different templates)

My tests with jsRender were successful, so i told myself, maybe you can add to this more dynamism by using jsViews (i mean by letting jsViews automatically update the dom when data is updated).

The thing is i can't in that case, because i have to different templates (one while upload is in progress, and one after it's done) that can't be appended to the same container element.

We can't link two data structures to the same element. Maybe that's logic by nature, but still, i have to ask, can i have the behaviour i expect with jsViews ?

Thanks.
Benjamin.

Support for jQuery plugin.

Why was demo "19 Custom tag for jQuery plugin: Datepicker" deleted from the latest Samples from jQuery Conference, Boston, October 2011?

My code that worked with the previous version now returns the following message "Error: Object doesn't support property or method 'apply'.

ChrisWF

Syntax to get the view index is different

The syntax to get the view index should be the same when using the JavaScript directly or the data-getfrom:

data-key="{{=$view.itemNumber-1}}" data-getfrom="class:$ctx.myFunction($view[index])"

Overridden String class

Just a rare case, but it is worth adding a type check on primitive types.

In my case the code is used under some bigger projects, and the project is built upon a framework that overrides the primitive string type.

To make it easy, the var a = "";" will render a as classStringinstead of the plain""`.

And specifically it will affect the code in jquery.views.js at line 472:

cnvt = cnvt ? (cnvt + "." + param) : param;

While cnvt ? will return true because cnvt is an object of type String.

I have edited the line as follow, and things are running just fine now.

cnvt = typeof cvnt == "string" && cnvt.length ? (cnvt + "." + param) : param;

Wrong nodeType / linkedView in nested arrays?

Simple code to produce the bug:

$.templates("tpl", "#tpl");

// Link to a simple data structure
$.link.tpl(".result", [[1], [2]]);
<script id="tpl" type="text/x-jsrender">
{{for #data}}{{for #data}}}{{:#data}}{{/for}}{{/for}}
</script>

<div class="result"></div>

Then we can have the following script error in Webkit,

Uncaught TypeError: Cannot call method 'push' of undefined                     jquery.views.js:507

Regex for detecting tmpl comment fails on function calls

A tmpl comment will not be correctly detected by the regex if the template tag param included a function call.

rTmplOrItemComment = /^(\/?)(?:(item)|(?:(tmpl)(?:\(([^,)]*),([^,)]*)\))?(?:\s+([^\s]+))?))$/,

The path portion of this expression ends if it sees a ), but the path could have a ) if a function was called.

Need support for Array concat method in observable

Need to support the concat method in the array for observable array. This will help to add a bunch of items and update the view with a single render call. I guess currently we need to add one item at a time to the array and this will trigger the array change event for every item added resulting in too many dom changes.

If data-to applied elements have additional logic for validation/value-check underlying model is not updated

Dear All,

I have the following example:

<div id="rr" style="background-color: Lime">

</div>

<script id="rrTemplate" type="text/x-jquery-tmpl">
    <p>
        <span>Number of full rounds:</span>
        <input data-getfrom="[NumOfFullRounds]" data-to="[NumOfFullRounds]" class="numericValue"/>
    </p>
    <p>
        Reps in partial round:
    </p>

    {{#each RepetitionItems}}
        <div>
            <span><input id="txtRep{{=Id}}" data-getfrom="[Value]" data-to="[Value]" class="numericValue XXX"/></span>          
            <span data-getfrom="[Value]"></span>
        </div>
    {{/each}}
</script>

<script type="text/javascript"> 

    $(document).ready(function () {

             var regVM = {"NumOfFullRounds":5,"RepetitionItems":[{"Max":2,"Value":0,"Id":"A1"},{"Max":4,"Value":0,"Id":"A2"},{"Max":6,"Value":0,"Id":"A3"}]};

        alert('start');

        $("#rr").link(regVM, "#rrTemplate", {
            onAfterCreate: function(view) {
                if(view.parent.path == "$data.RepetitionItems")
                {
                    var actRep = view.data;
                    $("#txtRep" + actRep.Id).jStepper({minValue:actRep.Min, maxValue:actRep.Max}); //this code breaks the 'binding', underlying model will not be updated anymore!
                }
            }
        });
    });
</script>

jStepper is a 'plugin' which allows minvalue and maxvalue definitions for textboxes. These textboxes in this example have data-from and data-to attriutes pointing to the same property of a RepetitionItem.

After the jStepper code is executed, and I change values in the textbox, the jstepper code runs properly, but the underlying model is not updated (spans after the textbox listen to the model).

What is the best-practice for this scenario?

Also, doing the "if(view.parent.path == "$data.RepetitionItems")" statement in the event handler seems hacky, what happens if I have more complex templates, is there an easier way to accomplish this?

Or shall I put the {{each}}-content into different template, and then I can somehow hook for its onAfterCreate event?

Thanks!

Inside {{#each}} you can only access the data you're iterating over

Hi,
I really like JsRender/JsViews, but I'm puzzled about one thing.
When using {{#each}}, it seems I can only access data from the array I'm iteration over. In the example below I cannot access "CurrentValue" within the each iterator.

This is how my json data looks:
tasks = [
{
CurrentValue: { Id: 0, Description: "some value" },
ValidValues: [
{ Id: 0, Description: "some value" },
{ Id: 1, Description: "second value" },
{ Id: 2, Description: "third value" }
]
}]

Inside the template:

Acessing CurrentValue is no problem:
Value:{{=CurrentValue.Id}}

{{#each ValidValues}} Inside the iterator i can no logner access CurrentValue {{#if CurrentValue.Id == Id}} // Error: $data.CurrentValue is undefined. {{=Description}} {{else}} {{=Description}} {{/if}} {{/each}}

Add support for '}' characters within string literals in data-link expressions

Hi Boris,

Trying to upgrade from the previous version I encountered the following issue.

I use data-link converter functions as follows:
data-link="{:~formatterFunc('Showing {0} items in {1} folder', ItemCount, FolderName)}"

Where formatterFunc helper is something similar to String.Format in .NET.

With your latest bits I get an error during a call to $.link("#container", data)
“Unterminated string constant”.

If I remove the {0} and {1} from the string, it works fine. Also if was working with the last version of jsViews.

Error is coming form
function linkViews( node, parent, nextNode, depth, data, context, prevNode, index ) { .. }, which seems to be parsing the string literals.

It is turning out to be a great library so far, keep up the great work.

Thanks.

Illegal Assignment Error in jquery.views.js (IE 8)

If I use IE 8 to run your jsViews demo at the following URL :

http://borismoore.github.com/jsviews/demos/step-by-step/01_rendering-and-linking.html

or after downloading and running on my machine, I receive an "Illegal Assignment" error in IE 8 in jquery.views.js, on line containing : window = window | global. After commenting out this line, it works fine in IE 8.

Is this expected behavior? Can I continue using jsViews with that line commented out? I would like to use jsViews in IE 8 if possible. It works fine in FF and Chrome, IE only has that error.

Thank you,
JJ

Exception removing views

An exception is thrown when removeViews is called a template tag has its link property set to false. The line in removeView

parentElViews = parentElViews || jsViewsData( view.nextNode.parentNode, viewStr ),

will throw an exception in some cases because view.nextNode is undefined.

Use of helper functions in link()-ed views requires passed-in context

Consider a test template:
<script id="movieTemplate" type="text/x-jquery-tmpl"> <tr> <td>{{=Title}}</td> <td> {{#each $ctx.objectPropertiesToArray(Properties)}} <div> <em>{{=key}}</em> <em>{{=value}}</em> </div> {{/each}} </td> </tr> </script>

along with a registered helper function to support this template:

    var helperFuncs = {
        objectPropertiesToArray : function( object ){
            var ret = [];
            for (key in object) {
                if (!object.hasOwnProperty(key)) continue;
                ret.push({"key" : key, "value" : object[key]});
            }
            return ret;
        }
    };
    jQuery.views.registerHelpers(helperFuncs);

and then you render this template:

$( "#movieList" ).html($( "#movieTemplate" ).render( movies ));

everything works fine.

However, if you "link()" this same call:

jQuery("#movieList").link(movies,"#movieTemplate");

then the template is rendered correctly, but the following error ocurrs in the console log

$ctx.objectPropertiesToArray is not a function
[Break On This Error] "with($data){return [" + paramString + "];}")( $, source, view, view.ctx );
jquery.views.js (line 353)

The workaround is to pass any used $ctx functions into the "link()" call on the context object:

jQuery("#movieList").link(movies,"#movieTemplate",helperFuncs);

I believe the intended fix here is to augment the link()-ed context object with the "$ctx" so that both items passed in via the "context" argument to link() are available, as well as having the registered helper functions available in the view evaluation context.

input type='checkbox' not working properly in new version

In previous version (before Mar 6 update), I used this syntax to get and set value for checkbox:

 <input data-getfrom="checked:Alarm" data-to="Alarm" type="checkbox"/> 

If I use the new syntax like this:

<input data-link="Alarm" type="checkbox" />

If Alarm property is set to true, it doesn't show as checked at the checkbox. However, I can see that in the view model, the property can be updated when user check or uncheck the checkbox.

What should I do for the new version?

Jsviews relies on structure?

Ive built some custom helpers and some templates to pivot tables
.
This requires me to open the table tag, check proceeding rows to see if they belong to they table and add them , when the next proceeding row does now match, close the table.

This works fine and beautifully with jsrender, no errors, nice clean code.

However when I use jsview's data-getfrom="[dataName]" type tag it falls over.
The error in console is - "template is undefined" - template = template.split( "=" ) - line 236..

To ensure that the problem is the tags not being closed, i used the same helpers and removed all the table stuff and just wrapped the data with <div></div>. This works as expected

However if I was to wrap the data with only the starting <div> tag, it breaks..
What is the reason for this, does jsviews check or rely on the structure of the fields parent html elements?

I hope my message is clear and understandable.

Problems with data-linking in nested views

Hi!

I changed the Accordion Demo to allow editing using data-linking. Everything works fine:
http://jsfiddle.net/webwurst/A33LN/

Then I placed the button-header-row in a separate template and called it from all the other templates. The event-handler of the buttons has to change their parents view and it seems to work fine:
http://jsfiddle.net/webwurst/Z4vHX/

^But editing gives an Error now. It gives:
"$.observable(target).setProperty is not a function"

Bug? Or am I doing something wrong?
Regards!

cancel and validation on data linked edit form

This is more an advice question instead of an issue. I created an table and use the link function to render the rows. Then when an edit button is clicked I change a row to an edit template. I took this technique from the accordion example and it works perfectly.

In the row there is also an cancel button when in edit mode. However because of the datalinking I no longer have the original object and thus I cannot change back to the original values.

I have several options here. I can request the original object from the server or I can use one of the clone scripts to store a copy of data on the view object. Both these options have their disadvantages. Is there a better way of implementing a "cancel" functionality? Maybe there is an option for delayed binding with an hook or something....

sharing templates amongst template users

Hi,

I've tried to use to use a template that is not directly as a script tag in the dom. E.g. modified jsrender demo 01_inserting-data.html like:

< script id="movieTemplate" type="text/x-jquery-tmpl" src="t.html" >

This doesnt work.

But what are templates good for if they can't

  1. be viewed/modified by a designer
  2. shared amongst several webpages that show the same things

Or am I missing something? In any case, there is no demo that shows how to do that and the way above doesnt do it.

Best
no gece

Right data-link syntax

Hi Boris,

Your step-by-step samples seem to be using the folowing data-link syntax:

css-attrName{:~helperFunc(dataPropertyPath)}

This works for the first-time linking via $.link("#container", data), but does not seem to reflect subsequent data changes through calls to $.observable(data).setProperty('propertyPath', propertyValue);

On the other hand I found that if I move the semicolon before the opening curly bracket it seems to work better and not only dislplays the first-time value but subsequent value changes as well.

css-attrName:{~helperFunc(dataPropertyPath)}

Any idea what is going on here and which is the right to use?

Thanks again.

data-getfrom="[a.b]" does not update when setting a to an object

/Currently the following scenarios do work:
$.observable(model).setProperty("a.b", "bar");
$.observable(model.a).setProperty("b", "bar");

TODO Add support for $.observable(model).setProperty("a", { b: "bar" });
Need to iterate over paths paths = getLinkFromDataInfo( target, source ).paths - in addition to the one whose key is sourcePath

Linking from textarea picks up old value

If fromHandler is "html" and $source is a textarea element, the value is picked up from the textarea element property "text".
However, this is the old unchanged value, so the linking does not work properly.

(The new value is found in the "value" property of textarea. Changing "text" to "value" seems to work fine.)

Update: although, it seems to introduce problems in IE8...

Radio buttons with checked="checked" are not rendered checked

I'm trying to build a page that has a template that contains multiple radio button groups. The problem is that when the template renders the radio buttons that have the checked property in the source HTML are not visually checked in the browser. Unfortunately I cannot include a screenshot here to show it, but my test page is below. Groups with names ending in 1 to 3 are rendered by the template engine. 4 to 6 are plain HTML. 4 to 6 show fine 1-3 do not. This behavior is the same across Firefox, chrome and IE9. During my test I noticed that some browsers (FF) were showing the same problem in rendering checked on the no-template HTML groups if I omitted the form tags. Maybe I'm missing something obvious, If so don't hesitate to point it out to me.

btw. the missing docs on jsrender and view plugin forces me to look thru the source code of the plugins to identify the features and figure out their use. I have learned a few thing things from that! It's a great plugin.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>test</title>

    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.js"></script>

    <script src="/Scripts/jsrender.js" type="text/javascript"></script> 
    <script src="/Scripts/jquery.observable.js" type="text/javascript"></script>    
    <script src="/Scripts/jquery.views.js" type="text/javascript"></script>

    <script src="Scripts/date-en-US.js" type="text/javascript"></script>

</head>
<body>
    <script id="TemplateTest" type="text/x-jquery-tmpl">    

        <div data-getfrom="css-background-color:bgColor($view[index])">

            <input type="radio" name="Price{{=Id}}" data-getfrom="checked:[PriceType] == 2" /><span>Not Specified</span>
            <br />

            <input type="radio" name="Price{{=Id}}" data-getfrom="checked:[PriceType] == 0" />10
            <br />

            <input type="radio" name="Price{{=Id}}" data-getfrom="checked:[PriceType] == 1" />20
            <br/>       
            <br/>       


            <input type="radio" name="SearchArea{{=Id}}" data-getfrom="checked:[SearchAreaType] == 2" /><span>Not Specified</span>
            <br />

            <input type="radio" name="SearchArea{{=Id}}" data-getfrom="checked:[SearchAreaType] == 0" />30
            <br />

            <input type="radio" name="SearchArea{{=Id}}" data-getfrom="checked:[SearchAreaType] == 1" />40
            <br/><br/>

            <input type="radio" name="AdvertisementKind{{=Id}}" data-getfrom="checked:[AdvertisementKind] == 0" />All<br />
            <input type="radio" name="AdvertisementKind{{=Id}}" data-getfrom="checked:[AdvertisementKind] == 1" />Offered<br />
            <input type="radio" name="AdvertisementKind{{=Id}}" data-getfrom="checked:[AdvertisementKind] == 2" />Wanted<br />
            <br/>
        </div>

    </script>

    <script type="text/javascript">

        $().ready(function () {

            $("#TemplateTest").template("TemplateTest");

            var ads = [
                { Id: 1, AdvertisementKind: 0, SearchAreaType: 2, PriceType: 1},
                { Id: 2, AdvertisementKind: 1, SearchAreaType: 0, PriceType: 2 },
                { Id: 3, AdvertisementKind: 2, SearchAreaType: 1, PriceType: 0 }
            ];


            $("#testContainer").link(ads, "TemplateTest");
        });


        function bgColor(index) {
            return (index % 2 ? "yellow" : "red");
        }
    </script>
    <form action="About.aspx">
    <div id="testContainer"></div>

    <div id="Div4">

        <div style="background-color: blue;">

            <input type="radio"  name="Price4"/><span>Not Specified</span>
            <br/>

            <input type="radio" name="Price4"/>40
            <br/>

            <input type="radio" name="Price4" checked="checked"/>50
            <br/>       
            <br/>       


            <input type="radio" name="SearchArea4" checked="checked"/><span>Not Specified</span>
            <br/>

            <input type="radio" name="SearchArea4"/>60
            <br/>

            <input type="radio" name="SearchArea4"/>40
            <br/><br/>

            <input type="radio" name="AdvertisementKind4" checked="checked"/>All<br/>
            <input type="radio" name="AdvertisementKind4"/>Offered<br/>
            <input type="radio" name="AdvertisementKind4"/>Wanted<br/>
            <br/>
        </div>



        <div  style="background-color: yellow;">

            <input type="radio" name="Price5" checked="checked"/><span>Not Specified</span>
            <br/>

            <input type="radio" name="Price5"/>40
            <br/>

            <input type="radio" name="Price5"/>50
            <br/>       
            <br/>       


            <input type="radio" name="SearchArea5"/><span>Not Specified</span>
            <br/>

            <input type="radio" name="SearchArea5" checked="checked"/>60
            <br/>

            <input type="radio" name="SearchArea5"/>40
            <br/><br/>

            <input type="radio" name="AdvertisementKind5"/>All<br/>
            <input type="radio" name="AdvertisementKind5" checked="checked"/>Offered<br/>
            <input type="radio" name="AdvertisementKind5"/>Wanted<br/>
            <br/>
        </div>


        <div  style="background-color: blue;">

            <input type="radio"  name="Price6"/><span>Not Specified</span>
            <br/>

            <input type="radio"  name="Price6" checked="checked"/>40
            <br/>

            <input type="radio"  name="Price6"/>50
            <br/>       
            <br/>       


            <input type="radio"  name="SearchArea6"/><span>Not Specified</span>
            <br/>

            <input type="radio"  name="SearchArea6"/>60
            <br/>

            <input type="radio" name="SearchArea6" checked="checked"/>40
            <br/><br/>

            <input type="radio" name="AdvertisementKind6"/>All<br/>
            <input type="radio" name="AdvertisementKind6"/>Offered<br/>
            <input type="radio" name="AdvertisementKind6" checked="checked"/>Wanted<br/>
            <br/>
        </div>

  </div>
  </form>
</body>
</html>

Missing container causes attempt to derefence null

$.link.templateName('#no_element_with_this_id_exists', { 'data' : 'something'} );

results in attempt to dereference a null. This is because the link function( container, data, context, parentView, template ) does not verify that the selector actually selects any elements at line 759:

container = $( container )
        .bind( "change", dataToElem );
if ( template ) {
    // TODO/BUG Currently this will re-render if called a second time, and will leave stale views under the parentView.views.
    // So TODO: make it smart about when to render and when to link on already rendered content
    container.empty().append( template.render( data, context, parentView )); // Supply non-jQuery version of this...
    // Using append, rather than html, as workaround for issues in IE compat mode. (Using innerHTML leads to initial comments being stripped)
}
linkViews( container[0], parentView, undefined, undefined, data, context ); // <<<---- container[0] is undefined

changes in nested arrays don't trigger the dependent functions of a parent property

First of all I wan't to compliment you on your work on JSViews. I think data-driven views are the future off building web-application and that it will provide lot's of help with implementing your information-models within a information-system.

when you have got data like an order (see below), a properties like Total_Price and Total_lines depends on the data in the Orderlines array.

When rendering jsviews triggers a function that calculates the total price and the total amount of lines (this goes well).
However when changing a value within the orderlines, or add a line to the array with the array observable, jsviews doesn't trigger the functions depending on the property orderlines within the parent, so the amount of lines and the total price won't get updated.

If you need a full example please ask.

P.S. Is it possible to create nested context's or context's that are linked to just ONE property? And what are the possibilities of linking a model to your data to be sure a field contains validated values (creating toLinks should work fine, but can these links also be nested...)?

Thanks in advance,
Dennis

/*--- tmpl: #orderlineTemplate --*/
<script>
    
        
            
        
        
            
        
        
            
        
        
            
            
        
    
</script>

/-- tmpl: #orderTemplate --/

<script> {{each Orderlines content="#orderlineTemplate"}}
Totaal:
</script>

var OrderData = {
Orderlines : [
{
Product : "Product X",
Amount : 1,
Price_each : 1,
Price : 1
},
{
Product : "Product X",
Amount : 2,
Price_each : 2,
Price : 4
}
],
Total_price : 0,
Total_lines : 0
}

$("#orderContainer").link(OrderData,"#orderTemplate")

$( "#addOrderlineBtn" ).click( function() {
$.observable( OrderData.Orderlines ).insert( OrderData.Orderlines.length, {
Product : "Product",
Amount : 1,
Price_each : 1,
Price : 1
});
});

Get values from array with data-to

I try to use the link function with jsView to update the value of an array.

Here is the javascript (I am using backbone.js so the this.el is the current html element for the view):

that.viewModel = new Role();
that.viewModel.ModuleAccessList = [];
_.each(col.toJSON(), function (obj) { 
//col is a backbone collection that I convert to an json array with the toJSON()
  that.viewModel.ModuleAccessList.push({ Module: obj, Access: "" });
});
var content = $("#AddRoleTemplate").render(this.viewModel);
$(this.el).html(content);
$(this.el).link(this.viewModel);

And the HTML:

><table>
>   {{#each ModuleAccessList}}
>    <tr>
>        <td>
>            {{=Module.Name}}
>        </td>
>        <td>
>            <select data-to="[ModuleAccessList[{{=$itemNumber}}].Access]">
>                <option value="none">none</option>
>                <option value="readonly">readonly</option>
>                <option value="full">full</option>
>            </select>
>        </td>
>    </tr>
>    {{/each}}
></table>
></pre>

The value of the viewModel updates like :

ModuleAccessList[1].Access = "readonly" where ModuleAccessList[1].Access is a field.

Is there anyway to update the array directly with data-to and link ?

Consider an alternative to the "changeArray" syntax.

After browsing through jsviews, I was thinking about a different syntax for the changeArray function.

I forked the code to here:

https://github.com/wiredprairie/jsviews

In particular:

https://github.com/wiredprairie/jsviews/blob/master/demos/2_views/2_editable-data.html

My idea:

$.array($.view(this).data.Languages).push(
{
        Name: "NewLanguage"
});

Or this:

$.array(app.selectedItem.data.Languages).splice($.view(this).index, 1);
//$.changeArray(app.selectedItem.data.Languages, "splice", $.view(this).index, 1);

My suggestion is to use a more function based approach that could/might work better with VS2010 (and other IDEs) code completion and be a bit more natural. Here, I changed the syntax from the parameter based "push" to a full function that is called after accessing the array. This follows the jquery pattern of "selector", then function/action.

ArrayObservable Move has an error.

Line 150

triggerArrayEvent( this._data, { change: "move", oldIndex: oldIndex, index: index, items: items });

index is not defined anywhere. was this supposed to be newIndex?

Support <table> without <tbody>, <col> without <colgroup> etc., or provide parser error messages for all such cases.

The browser will insert <tbody> or <colgroup> dynamically, which will break JsViews.

Currently JsViews provides an error message during data linking, for the first case. (See #157). This issue concerns either supporting the data-linking without error, or adding more generic error message handling for all such cases at data-link time, or adding validation at template compile time (including tooling for compiling on the server), to detect this as invalid template markup.

See also BorisMoore/jsrender#47 and BorisMoore/jsrender#30

Problem linking object with div element

Hi,

I am using backbone.js, jsRender and jsView and I get a problem with the new version of jsView, my binding is no more working.

I have an input element and I am trying to link it with a viewModel (a json object) like

view.el.innerHTML = $.render["current"](view.viewModel);
$.link("#WorkingArea",view.viewModel);

with the input
<input data-link="Name" tabindex="1" placeholder="Company Inc." class="medium" type="text" />
<a href="#" class="save">save</a>

When I click on the save button, I get the view.viewModel and it's not updated with the value entered in the input.

NOTE : if I try with the old version of jsView (with the data-to in place of the data-link and by executing $("#WorkingArea").link(view.viewModel)),
it is working fine.

Any idea???

Here is the full code :

Company.Views.Create = Backbone.View.extend({
        el: "#WorkingArea",
        template: "app/templates/company/create.html",
        events: {
            "click .cancel": "close",
            "click .save": "save"
        },
        initialize: function () {
            this.model = new Company.Model();
            _.bindAll(this, "render");
        },
        render: function (done) {
            var view = this;

            // Fetch the template, render it to the View element and call done.
            MyApp.fetchTemplate(this.template, function (tmpl) {
                view.viewModel = view.model.toJSON();

               view.el.innerHTML = $.render["current"](view.viewModel);
              $.link("#WorkingArea",view.viewModel); 

                popWrapper.Pop($(view.el));

            });
        },
        save: function (event) {
            event.preventDefault();
            alert(this.viewModel.Name);

        },
        close: function (event) {
            this.remove();
            event.preventDefault();
            popWrapper.Close();
            popWrapper.CreateWorkingArea();
        }
    });

$.observable(array).insert(array.length,deltaData) broken on Chrome(pre beta commit #2)

This was working very good until pre beta commit #2. I have this issue only with Chrome. After I saw this problem, I returned to the previous version.

If you want to see my code here it is:

        view.off("click", ".showMore").on("click", ".showMore", function () {

            var item = this;

            //Get delta data.
            oAjax.CallAsyncMethod(JSON.stringify(param), false, serviceURL + '/Activity/GetDelta', "POST", function (data) {

              //insert it to client data.
                $.observable(exData.ViewData).insert(exData.ViewData.length, data.GetDeltaResult);

                param.DisplayCount += 20;

            });

        });

P.S: I can insert to exData.ViewData.length-1 or anywhere inside of current array, but not at the end. I think there is a problem with the last item of view/context etc. I don't know.

In IE 7 li tags with getfrom in top-level linking do not work

http://jsfiddle.net/cXZP6/10/ - in compat mode, activate then insert

<ul id="myfolderlist" style="display:inline">
    <!--tmpl() folderTemplate-->
    <!--item-->
    <li data-getfrom="[name]">[s]Folder 1</li>
    <!--/item-->
    <!--/tmpl-->
</ul>

The problem is that in initial page parsing, IE puts and as child nodes of the li, and then getfrom replaces the li content with the [name] data, before the IE7 fixup code reaches the and nodes.

Linking to descendant leaf objects

Hi Boris,

I am glad to see that you are making good progress with the new library and hope it will make it past beta this time.

I am binding to descendant leaf objects and making use of converter functions like so:

TEST
var data = {
Level1: {
Level2: 'ABC'
}
}
$("#element").link(data);

When I bind it first time the converter function gets called as expected

However when I change the underlying value, the converter function is not called:
$.observable(data).setProperty('Level1', { Level2: 'XVZ' });

I was digging around and narrowed the problem to the following code (jquery.views.js function addLinksFromData line 513)

// If 'from' path points to a property of a descendant 'leaf object',
// link not only from leaf object, but also from intermediate objects
while ( innerPath.length > 1 ) {
innerOb = innerOb[ innerPath.shift() ];
if ( innerOb ) {
addLinkFromData( innerOb, link, innerPath.join( "." ), cnvt, attr );
}
}
// The last trigger of get bindings will be called on adding the link (to get/initialize the value)
addLinkFromData( fromOb, link, 'Level1'/path/, cnvt, attr, !l && get );

As you can see in the last call to addLinkFromData, the path is ‘Level1.Level2’ but if I change it to the name of the root propery, which is 'Level1' in my case - everything works fine.

Please let me know if you agree that in the last call to the addLinkFromData the name of the root property property should be used in case of descendant leaf objects as it will be then used in addLinkFromData:

$(Level1).bind("propertyChange", handler);

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.