javascriptjavascript-frameworkcanjscanjs-model

Dynamic properties for CanJS model?


I would like to add dynamic properties in my model that is not in the REST service results. These dynamic properties would shorten names, format dates, etc. For example, my CanJS model like this:

var MyModel = can.Model({
    findAll: 'GET /Services/all'),
    findOne: 'GET /Services/{id}'),
    create:  'POST /Services/all'),
    update:  'PUT /Services/{id}'),
    destroy: 'DELETE /Services/{id}')
}, {});

Then I retrieve the data like this:

MyModel.findAll({}, function(data) {
    $('#main').html(can.view('templates/List.ejs'), data));
});

And this is how my List.ejs template looks like:

<% for(var i = 0; i < this.length; i++) { %>
    <div class="thumb"><img src="http://cdn.somewhere.com/images/logo.<%= this[i].BaseName %>.png" /></div>
    <div class="title"><%= this[i].Name %></div>
    <div class="date"><%= moment(this[i].StartDate).format('MMM DD, YYYY') %> - <%= moment(this[i].EndDate).format('MMM DD, YYYY') %></div>
    <div class="location"><%= this[i].LocationFriendly %></div>
    <div class="description"><%= this[i].Description %></div>
<% } %>

Notice the logic I am doing in the template for the image src and start/end dates. I would like to put this logic in the model so all I have to do in the template is this:

<% for(var i = 0; i < this.length; i++) { %>
    <div class="thumb"><img src="<%= this[i].ImageURL %>" /></div>
    <div class="title"><%= this[i].Name %></div>
    <div class="date"><%= this[i].StartDateFriendly %> - <%= this[i].EndDateFriendly %></div>
    <div class="location"><%= this[i].LocationFriendly %></div>
    <div class="description"><%= this[i].Description %></div>
<% } %>

How to I move this logic into the model layer or any better place then the template? Thanks for any help or advise.


Solution

  • The easiest way would be to just create functions on your model:

    var MyModel = can.Model({
        findAll: 'GET /Services/all',
        findOne: 'GET /Services/{id}',
        create:  'POST /Services/all',
        update:  'PUT /Services/{id}',
        destroy: 'DELETE /Services/{id}'
    }, {
        imageUrl : function(){
            return "http://cdn.location.com/" + this.BaseName + ".png"
        },
        startDateFriendly : function(){
            return moment(this.StartDate).format('MMM DD, YYYY')
        },
        endDateFriendly : function(){
            return moment(this.StartDate).format('MMM DD, YYYY')
        },
        locationFriendly: function() {
            // ...
        }
    });
    

    Then you can just call these functions from the view:

    <% for(var i = 0; i < this.length; i++) { %>
        <div class="thumb"><img src="<%= this[i].imageUrl() %>" /></div>
        <div class="title"><%= this[i].Name %></div>
        <div class="date"><%= this[i].startDateFriendly() %> - <%= this[i].endDateFriendly() %></div>
        <div class="location"><%= this[i].locationFriendly %></div>
        <div class="description"><%= this[i].Description %></div>
    <% } %>