EzDevInfo.com

knockback

Knockback.js provides Knockout.js magic for Backbone.js Models and Collections. Knockback.js Home

Knockback Collection Observable throws "Cannot read property 'bind' of undefined" error

I'm trying to make a simple viewmodel to display a list of objects with Knockback. The View Model is rather simple, looking like this:

var objectives_collection = new ObjectiveCollection();
objectives_collection.fetch();

var view_model = kb.ViewModel.extend({
    objectives: kb.CollectionObservable(objectives_collection),
    constructor: function() {
        _this = this;
        kb.ViewModel.prototype.constructor.call(this, model = new Objective(), {});
        console.log(this.objectives);
        return this;
    },
    addObjective : function() {
        var objective_model = new Objective({name: "New Objective", descriptor: 'Add description here'});
        this.objectives.add(objective_model);
        objective_model.save();
        console.log(objectives);
    },
    edit: function() {
        console.log('Edit');
    },
    remove: function(objective) {
        self.objectives.remove(objective);
    }

});

Right now though, the first line of the view model (kb.CollectionObservable(objectives_collection)) is giving me grief. It's calling Underscore.js' bind function and trying to set up the onCollectionChange listener, but Knockback's line here is trying to bind an undefined function:

this.__kb._onCollectionChange = _.bind(this._onCollectionChange, this);

where this._onCollectionChange is apparently undefined. I'm not really sure what to make of this; what am I doing wrong here?


Source: (StackOverflow)

How can I get KnockBack CollectionObvservables as KnockOut observableArrays?

I am using KnockBack (w/ KnockOut & BackBone) and am having trouble getting KB CollectionObservable (CO) values in the same format as KO's ObservableArrays. This is the core essence of KB, of course -- allowing me to use BB models with KO's data-binding; this is why I am so surprised I can't get/use the same syntax to expose the data to the data-binding.

Consider the following:

x = ko.observableArray([[1,2],[3,4]])

//x() == [Array[2],  Array[2]]

y = kb.collectionObservable(new Backbone.Collection([[1,2],[3,4]]))

// y() == [ViewModel, ViewModel]

So, assuming I have such a kb.collectionObservable, how can I easily extract its values as an array of arrays, to be used with KO-compatible APIs?


Source: (StackOverflow)

Advertisements

Implementing a Many-to-Many relationship with Backbone-Relational

I have a simple application which defines two classes, a Person and a PersonGroup, wherein there is a many-to-many relationship in place. A Person can have no group, or be assigned to all groups, and anything in between.

The example on backbonerelational.org suggests using an in-between model for many-to-many relationships, however I can't get this pattern to work with fetching (deserializing) and saving (serializing).

What I want to do is use Backbone to deserialize a JSON similar to the following:

{
    People:
    [
        {
            "ID": 1,
            "Name": "John"
        },
        {
            "ID": 2,
            "Name": "Bob"
        },
        {
            "ID": 3,
            "Name": "Tim"
        },
    ],
    PeopleGroups:
    [
        {
            "ID": 1,
            "Name": "Owners",
            "People":
            [
                1,
                2
            ],
        },
        {
            "ID": 2,
            "Name": "Everyone",
            "People":
            [
                1,
                2,
                3
            ],
        },
    ]
}

I'm using Knockback/Knockout for data binding so the problem is I need to be able to access the relationships by reference. An array of IDs does not do me any good, unless I can create a Knockback.CollectionObservable to wrap the collection and resolve the IDs to references.


Source: (StackOverflow)

Using Knockoutjs & Backbone together

I'm a real big fan of knockoutjs. I've see a number of posts saying that knockoutjs & backbone work well together. But I'm having trouble getting started with backbone and don't understand how the two can be used together. Are there any resources that would show how to use knockoutjs and backbone together?

Note, I'm not looking for a discussion about which is better. There are enough posts on this point.


Source: (StackOverflow)

Is Knockback.js production ready? [closed]

I've used Backbone.js, I've learned about Knockout.js; however, now I found out about Knockback.js. It is supposed to get the best out of the other two tried& proven frameworks. Do you have any experience with Knockback in production? I'm wary to use it since it doesn't seem to be mature enough.


Source: (StackOverflow)

Backbone.js Model Sync claims URL Undefined

I'm trying to make a new Backbone model (working within Knockback) and I'm currently trying to set it up with a RESTful backend server. The issue is that the URL isn't accepted when trying to use the objectives.sync(). It works normally when doing objectives.fetch() however, and correctly pulls the data from the specified URL. What am I doing wrong here?

/**
 *  Objectives model
 */
var Objective = Backbone.Model.extend({
    url: 'api/objective',
    // Defaults
    defaults: {
        category: null,
        weight: null,
        name: null,
        descriptor: null
    }
});
/**
 *  Basic objectives collection
 */
var ObjectiveCollection = Backbone.Collection.extend({
    model: Objective,
    url: function() {
        return "api/objective";
    },
    initialize: function(models,options) {}
});

The code to actually make use of this collection can be seen here:

var objectives = new ObjectiveCollection();
objectives.fetch();
var view_model = {
    objectives: kb.collectionObservable(objectives, {view_model: kb.ViewModel})
};
ko.applyBindings(view_model, $('#objectives').get(0));
// Listener for the click button
$('#click').click(function() {
    counter++;
    var objective_model = new Objective({name: Math.random(), descriptor: 'What up'});
    objectives.add(objective_model);
    objectives.sync();
});/**/

Source: (StackOverflow)

JQuery toggle div inside the foreach loop

I am using knockback.js.I have a list of values "projects"(value comes from the server). and the content of these values are displayed in the <div class="hiddendivcontent"> .

<ul data-bind="foreach: projects" class="list-group">

     <li class="list-group-item" data-bind="click: function(data,event){CommunityView.showContents($data.pkey(),$data.folder(), data, event);}">
          <span style="border:0px;" class="glyphicon glyphicon-plus pull-right" data-toggle="dropdown" ></span>
          <ul class="dropdown-menu labellistdropdown" role="menu" style="min-width:200px;">
              <li>..</li>
          </ul>
          <div  class="hiddendivcontent">
              <ul data-bind= "foreach : $root.community()" class="list-group">
                   <ul data-bind = "foreach :items">
                     <li> <span data-bind="text:cname"></span></li>
                   </ul>   
              </ul>
           </div>    
    </li>  

 </ul> 

The "hiddendivcontent" gets the value when "CommunityView.showContents()" is clicked. In other words,"hiddendivcontent" should be displayed when the method is clicked otherwise it remains hidden. The following code is the Jquery code that i have used :

showContents : function(pk,rf,data,event){
            event.preventDefault();
            $('.hiddendivcontent').toggle(); 
    }

If I use this above code the value is populated in all the list items. I have tried many ways to toggle the div but nothing works. Can anyone please suggest me any ideas?

Thanks in advance


Source: (StackOverflow)

How do I resolve this race condition with knockout and capybara?

I have a page that's rendering a wijmo combobox via the wijcombobox knockout binding ( http://wijmo.com/wiki/index.php/Using_Wijmo_with_Knockout ). I'm having difficulty testing this using capybara because of a race condition between the tests running and the click event being bound. There are possibly other race conditions as well, but this is the current one tripping me up. This is what I have as a current workaround:

def click_on_combobox_till_options_appear
  wait_until(10) do
    page.find('.wijmo-wijcombobox-trigger').click
    page.has_css?('.wijmo-wijlist-item')
  end
end

I'm using 'kb-inject' to setup my ViewModel bindings.

Is there a javascript event I can hook up to or property I can test to indicate that applyBindings has finished executing, so that I can avoid workarounds like the one above?


Source: (StackOverflow)

Backbone.LocalStorage saves but does not fetch collection using Knockback

Backbone.LocalStorage stores a list of players client-side when calling create on a players collection, but the stored models are not being fetched later, even though I can inspect them in localStorage. I can call @collections.players.localStorage.findAll() to retrieve all the stored objects and manually push them onto my collection.

class App.Models.Player extends Backbone.Model
    defaults:
        name: 'Unnamed'
        team: 'Unassigned'

class App.Collections.Players extends Backbone.Collection
    localStorage: new Backbone.LocalStorage('players')
    model: App.Models.Player

class App.ViewModels.Game extends kb.ViewModel

    constructor: ->
        @collections =
            players: new App.Collections.Players()

        @collections.players.fetch(
            success: (collection) =>

                console.log(collection) # shows none
                console.log(@collections.players.localStorage.findAll())
                    # shows all the stored players
        )

        # @players below is rendered by a foreach in a knockout template
        @players = kb.collectionObservable @collections.players, { view_model: App.ViewModels.Player }

    addPlayer: -> # called when a button is pressed
        @collections.players.create(new App.Models.Player({ name: 'New Player' }))
        return

Why is Knockback unable to fetch the stored entities automatically?

The following call manually retrieves all objects:

_.each @collections.players.localStorage.findAll(), (elem) =>
    @collections.players.add(elem)

Source: (StackOverflow)

Populating the hidden field in Javascript

I am using Knockback.js. I am a newbie to this whole javascript and html. I am trying to poplulate the hidden field in the function addFolder, But it always showing null. This is the following javascript code(viewmodel).

GroupsView = LS.ViewModel.extend({
initialize : function(options) {
if(typeof options != 'undefined'){
        this.projectskey = options.projectskey;
        this.folderkey = options.folderkey;
    }
    this.options = options;
    this._this = this;
    this.c = new GroupsCollection(null, options);
    this.c.fetch({
        add : true
    });
    this.groups = kb.collectionObservable(this.c);
},
fetch : function() {
    $('#loadingAnim').show();
    this.groups.collection().fetch({
        update : true,
        add : true
    });
},
addFolder: function(vm, event){
    event.preventDefault();

    $("#plgGroupsGetContents").val(vm.projectskey); 
    $("#plgGroupsGetContents1").val(vm.folderkey);
    vm.c.addFolder();
    $('#dialogAddFolders').modal('hide');
}

});

and this is the following html code

 <form action="/groups/createfolder" id="addFoldersForm" data-bind="event: {submit: $root.addFolder.bind() }">
<div class="modal-dialog">
    <div class="modal-content">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
            <h4 class="modal-title" id="myModalLabel" data-bind="text: LANG.getText('plgGroupAddFolder')"></h4>
        </div>
        <div class="modal-body">
            <input type="hidden" name="projectskey" id="plgGroupsGetContents" value="">
            <input type="hidden" name="rootfolder" id="plgGroupsGetContents1" value="">
            <span data-bind="text: LANG.getText('plgGroupFolderName')"/><input type="text" data-bind="attr: {placeholder: LANG.getText('plgNameDefaultText')}" required title="Folder name" name="foldername" data-icon="U"><br>       
         </div>
        <div class="modal-footer">
            <button data-bind="text: LANG.getText('plgGroupAbort')" type="button" class="btn btn-default" data-dismiss="modal"></button>
            <button data-bind="text: LANG.getText('plgGroupAddFolderOKBtn')" class="btn btn-primary"></button>
        </div>
    </div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->

Can you please suggest me some ideas. Thanks in advance


Source: (StackOverflow)

Filtering a collection of view models in using Knockback.js

I am currently creating a page using Knockback.js that displays an employee's tasks in a table. I have a view model for a task, which contains a boolean observable called isSelected. The view model for an employee contains a collection observable of a collection of task view models called 'tasks'.

I now want to add an attribute/function/observable called 'selectedTasks' which only exposes the selected tasks. I want to meet the following requirements:

  • Both the 'tasks' and 'selectedTasks' should give me view models, not models.
  • When I add a model to the original tasks collection, the 'tasks' observable should get updated.
    • When the user selects this newly added model, the 'selectedTasks' should get updated as well.
  • There should be only one view model for every task model. Otherwise I might get a view model that states task x is not selected while another view model states that x is selected.

To demonstrate it a bit more clearly, I created this jsfiddle: http://jsfiddle.net/drojoke/cg6d88Lp/14/

So far, I only managed to get everything working for the 'tasks' attribute using a collection observable, as seen here:

this.tasks = kb.collectionObservable(tasks, {
    view_model: function (task) {
        return new TaskViewModel(task);
    }
});

I'm using the view_model option to turn every task in the tasks collection into a TaskViewModel. When I add a new task to the tasks collection, the CollectionObservable is updated as exptected.

I tried to create a selectedTasks attribute as a CollectionObservable with a filter option, like so:

this.selectedTasks = kb.collectionObservable(tasks, {
    view_model: function (task) {
        return new TaskViewModel(task);
    }, filters: function (task) {
        return task.isSelected(); // isSelected is undefined.
    }
});

But unfortunately, the object that gets passed to the filters function is not a TaskViewModel, but just a task object, so I have no access to the isSelected observable.

I couldn't find a lot about filtering a collection of view models instead of models. How can I created a selectedTasks observable that filters view models and doesn't create additional view models?


Source: (StackOverflow)

How to get the underlying Backbone Collection in a Knockback CollectionObservable from the $data context object with nested templates

Taking the following code snippet as a quick example:

var Animal = Backbone.Model.extend();
var Zoo = Backbone.Collection.extend({ model: Animal });

var tiger = new Animal({ name: "tiger" });
var zoo = new Zoo(tiger);

var viewModel = {
    tiger: kb.viewModel(tiger);
    zoo: kb.collectionObservable(zoo);
}

ko.applyBindings(viewModel);

from the $data context you can get a reference to the tiger model:

tiger === $data.tiger().__kb.object;

or

tiger === $data.zoo()[0].__kb.object;

and I assume it exists somewhere on this dependantObservable function, but I can't seem to find the reference to the original Backbone Collection

$data.zoo

Does anyone have any idea of how to get at the original Backbone Collection?

Also, bonus points if you can tell me of any way to get at the Backbone Collection if the viewmodel is this instead:

viewModel = kb.collectionObservable(zoo)

the challenge here is that $data contains the results of the evaluated dependantObservable function.


EDIT After receiving a perfectly valid answer to the question above I realized that my problem only occurs in my more complicated binding with nested templates:

The templates look like this:

    <!-- outer template -->
    <script type="text/html" id="tmpl-outer">
        <button data-bind="click: $root.outerContext">Outer Context</button>
        <div data-bind="template: { name: 'tmpl-inner', data: collection }"></div>
    </script>

    <!-- inner template -->
    <script type="text/html" id="tmpl-inner">
        <button data-bind="click: $root.innerContext">Inner Context</button>
        <div data-bind="foreach: $data">
            <button data-bind="click: $root.modelContext">Model Context</button>
        </div>
    </script>

Model and View-Model:

var model = new Backbone.Model();
var collection = new Backbone.Collection(model);

var viewModel = {
    collection: kb.collectionObservable(collection),
    outerContext: function (data) {
        console.log(data.collection.collection() === collection);
    },
    innerContext: function (data) {
        console.log("??????? === collection");
    },
    modelContext: function (data) {
        console.log(data.model() === model);
    }
};

ko.applyBindings(viewModel);

And finally, somewhere to render everything:

<body>
    <div data-bind="template: { name: 'tmpl-outer' }"></div>
</body>

So, my initial question that I over-simplified my example for should have been: how do I get at the underlying collection on the line:

console.log("??????? === collection");

It appears that the collection in this context has been converted to a simple KnockOut observable array - there doesn't seem to be any of the important KnockBack properties.


Source: (StackOverflow)

Knockback.js backbone collection only adds first element to UI

I'm trying to set something new up with Knockback.js, and right now I'm running into an issue with the knockout/knockback integration. The problem is, I've successfully written an event handler which adds a new model to the Objectives collection, but the UI only registers and adds the first such addition. It does successfully add the new objective to the list, but only the first one--after that, while the collection does successfully add a new model to the list, it doesn't appear in the UI.

<a class="btn" id="click">Click me!</a>
<div id="objectives" data-bind="foreach: objectives">
    <h3 data-bind="text: name"></h3>
</div>

And this script:

// Knockback script MUST be located at bottom of the page
$(document).ready(new function() {
// instantiate the router and start listening for URL changes
var page_router = new PageRouter();
Backbone.history.start();

// Get JSON value
var objectives;
$.getJSON('json.php', {table: 'objectives'}).done(function(data) {
    objectives = new ObjectiveCollection(data);
    var view_model = {
        objectives: kb.collectionObservable(objectives, {view_model: kb.ViewModel})
    };
    ko.applyBindings(view_model, $('#objectives').get(0));
});
$('#click').click(function() {
    var objective_model = new Objective({category: 3, name: Math.random(), descriptor: 'What up'});
    objectives.add(objective_model);
    console.log(objectives);
});
});

Where the only custom models are as seen here:

/**
 *  Objectives model
 */
var Objective = Backbone.Model.extend({
// Defaults
defaults: {
    id: null,
    category: null,
    weight: null,
    name: null,
    descriptor: null
},
// Url to pass to
url : function() {
    // Important! It's got to know where to send its REST calls. 
    // In this case, POST to '/donuts' and PUT to '/donuts/:id'
    return this.id ? '/objectives/' + this.id : '/objectives'; 
}

});
/**
 *  Basic objectives collection
 */
var ObjectiveCollection = Backbone.Collection.extend({
    model: Objective,
initialize: function(models,options) {}
});

Source: (StackOverflow)

Knockback: Remove item from an observable collection

Given an observable collection in Knockback, how do I remove an item from the underlying collection in response to a knockout.js click event?


Source: (StackOverflow)

Knockback.js: How can I make the view update when backbone save updates the model?

This is my first time working with Knockback.js.

I'm working on a Knockback proof of concept, but I'm having a hard time getting the view model to update when I save a model. In this case, what happens is the server returns a new Domain object with the id field set, which means that the object now exists on the backend. Once that happens, I would like the UI to change to reflect the fact that it is now saved.

Here is the code I'm using:

<table cellspacing="0" class="listing-table" id="domainListTable">
    <thead>
        <tr>
            <th scope="col">
                Domain
            </th>
        </tr>
    </thead>
    <tbody data-bind="foreach: domains">
        <tr>
            <td>
                <!-- ko if:save -->
                    <a data-bind="attr: { href: domainEditLinkdomainId, title: domain},text : domain">
                        <span data-bind="text: domain"></span>
                    </a>
                <!-- /ko -->
                <!-- ko ifnot:save -->
                    <input type="text" maxlength="250" style="display:inline-block;" class="medium-text-field" data-bind="value: domain"></input>
                    <input data-bind="click: save" style="display:inline-block;"  type="submit" value="Save New Domain" alt="" title=""/>
                <!-- /ko -->
            </td>
        </tr>
    </tbody>
</table>
<br />
<input data-bind="click: addDomain" type="submit" value="Add New Domain" alt="" title=""/>

<script type="text/javascript">
    var Domain = Backbone.Model.extend({
        defaults: function() {
          return {
            domain: "New Domain"
          };
        },
    });

    var Domains = {};

    Domains.Collection = Backbone.Collection.extend({
        model: Domain,
        url: '/cms/rest/poc/${customerId}/domains/'
    });

    var domains = new Domains.Collection();
    domains.fetch();

    var DomainViewModel = kb.ViewModel.extend({
        constructor: function(model) {
            kb.ViewModel.prototype.constructor.apply(this, arguments);

            var self = this;

            this.save = kb.observable(model, {
              key: 'save',
              read: (function() {
                return !model.isNew();
              }),
              write: (function(completed) {
                return model.save({}, {
                    wait: true,
                    success: function (model, response) {
                        console.log(model);
                        console.log(response);
                        console.log(self);
                    },
                    error: function(model, response) {
                        alert("Oh NooooOOOes you broked it!!!11!")
                    }
                });
              })
            }, this);

            this.domainEditLinkdomainId = ko.dependentObservable(function() { 
                if(!this.save())
                    return "";

                return "cms?action=domainDetail&domainID=" + this.model().id;
            }, this);
         }
    });

    var DomainsViewModel = function(collection) {
        this.domains = kb.collectionObservable(collection, { view_model: DomainViewModel });
        this.addDomain = function() {
            this.domains.push(new DomainViewModel(new Domain()));
        };
    };

    var domainsViewModel = new DomainsViewModel(domains);

    ko.applyBindings(domainsViewModel);
</script>

The problem seems to be that the XMLHttpRequest done by model.save() does not return until after the save kb.observable is read, and so the html part does not update successfully, since it still sees model.isNew() as true.

I've been messing around with a couple of different ideas, as you can probably see, including using the valueHasMutated method on an observable to indicate that the model has been updated, but I can't figure out how to do that either.

Any help would be greatly appreciated!


Source: (StackOverflow)