I might be missing something really simple but can anyone point out where i'm doing wrong here?
many thanks in advance.
<div data-bind="foreach: agencies">
<div data-bind="text:name"></div>
<div data-bind="text:email"></div>
<button data-bind="click: removeAgency">remove</button>
</div>
<script type="text/javascript">
var agency = [{
name : ko.observable('a'),
email : ko.observable('b')
}, {
name: ko.observable('c'),
email: ko.observable('d')
}];
var vm = {
agencies: ko.observableArray(agency),
removeAgency: function(agency) {
this.agencies.remove(agency);
}
};
ko.applyBindings(vm);
</script>
this is the error i get: Uncaught Error: Unable to parse bindings.
Message: ReferenceError: removeAgency is not defined;
Bindings value: click: removeAgency
You are binding to an agency in that html, but your method is on your viewmodel. Try something like:
<button data-bind="click: $parent.removeAgency">remove</button>
You might need to re-jig your vm to get the scope correct:
var ViewModel = function(){
var self = this;
self.agencies = ko.observableArray(agency),
self.removeAgency = function(agency) {
self.agencies.remove(agency);
}
};
var vm = new ViewModel();
I still get confused at times with scope, I have to admit, but give this a try and see what happens.
Working example:
http://jsfiddle.net/marko4286/7RDc3/2034/
Read documentation http://knockoutjs.com/documentation/foreach-binding.html
Related
I have to string concatenate value from resource file with KO observable string.
Here is what I tried
But I'm getting error message
Message: Office is not defined
at text (eval at parseBindingsString (knockout-3.4.0.js:68), :3:82)
at update (knockout-3.4.0.js:98)
at function.a.B.i (knockout-3.4.0.js:72)
at Function.Pc (knockout-3.4.0.js:51)
at Function.Qc (knockout-3.4.0.js:51)
at Function.aa (knockout-3.4.0.js:50)
at Object.a.m.a.B (knockout-3.4.0.js:49)
at knockout-3.4.0.js:72
at Object.q (knockout-3.4.0.js:11)
at m (knockout-3.4.0.js:71)
"Office is not defined" here Office is value I get from resource file for #Resources.Office.
can you pass your resource file into the viewmodel? then you should have access to it. run snippet below.
function model(Resources) {
var self = this;
this.Resources = ko.observable(Resources);
this.foo = ko.observable({
WorkPhone: true,
CellPhone: false
});
}
var Resources = {
'Office': '222-2222',
'OfficeMobile': '333-3333',
'Home': '444-4444'
}
var mymodel = new model(Resources);
$(document).ready(function() {
ko.applyBindings(mymodel);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind="with: foo">
<span data-bind="text: $data.WorkPhone ?
'Office: ' + $parent.Resources().Office +
' ,Office Mobile: ' + $parent.Resources().OfficeMobile
: 'Home: ' + $parent.Resources().Home"></span>
</div>
although I agree with Jose that a computed or pure computed is probably a better way to go.
My template is loading but I get an error that the controller is undefined. The controller does exist in my sources exactly at the location defined. What is wrong with this code?
Error: [ng:areq] http://errors.angularjs.org/1.2.14/ng/areq?p0=ItemsController&p1=not%20aNaNunction%2C%20got%20undefined
at Error (native)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:6:450
at xb
This is my html:
<div ng-app="myApp">
<ul ng-controller="ItemsController" class="nav">
<input type="text" value="ItemName" ng-model="newItemName" placeholder="name of new item...">
<button ng-click="addItem()">Add Me</button>
<li ng-repeat="item in items.data" id="item{{item.id}}">
{{item.title}}
<a ng-click="deleteItem($index)" class="fa fa-trash-o"></a>
</li>
</ul>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular-route.js"></script>
<script type="text/javascript" src="js/te.js"></script>
'use strict';
var myApp = angular.module("myApp", []);
myApp.factory("items ", function() {
var items = {};
items.data = [];
return items;
});
myApp.controller("ItemsController", function ItemsController($scope, items) {
$scope.items = items;
$scope.deleteItem = function(index) {
items.data.splice(index, 1);
}
$scope.addItem = function(index) {
items.data.push({
id: $scope.items.data.length + 1,
title: $scope.newItemName
});
}
});
The Only Problem I see in your code is in following line:
myApp.factory("items ", function() {
space in the factory name "items " and you are injecting in your controller as items.
Here is the working PLNKR of your code, proof its working fine.
Happy Helping!
I have faced this problem many a times and usually this is caused when you have not included your js in the template.
If its not the case, then if you could share your some part of code, then only anybody will be able to answer it properly.
I'm just getting started with Knockout.js and i have a view(html) which is supposed to be populated by data from a rest api via jquery's $.getJSON method.
When i run the app, nothing shows but using firebug i can see that the 'GET' query returns a status code of 200 and the right data.
I'm at a fix as to why nothing shows in the view since the bindings in Knockout.js are supposed to be automatic.
Below is my code.
Thanks
<div id ='main'>
<!-- ko foreach: posts -->
<p>Hello</p><span data-bind="text: title"></span></p><p data-bind="text: content"></p>
<p data-bind="text: author"></p><p data-bind="text: date"></p>
<!-- /ko -->
</div>
</body>
<script type="text/javascript">
function Post(data){
this.title = ko.observable(data.title);
this.content = ko.observable(data.content);
this.author = ko.observable(data.author);
this.date = ko.observable(data.date)
}
function PostListViewModel(){
var self = this;
self.posts = ko.observableArray([]);
$.getJSON("/posts", function(getPost){
var mappedPost = $.map(getPost, function(item){
return new Post(item)
});
self.posts(mappedPost);
});
}
var postlistviewmodel = new PostListViewModel();
ko.applyBindings(postlistviewmodel);
</script>
This should be:
$.getJSON("/posts", function(getPost){
var mappedPosts = $.map(getPost, function(item){
return new Post(item)
});
self.posts(mappedPosts);
});
wouldn't do self.posts.push(mappedPosts[i]) at all. You should just pass mappedPosts through the ko binding in order to update the listeners.
If your just getting the latest posts and want to update your current list simply do:
var allPosts = self.posts().concat(mappedPosts);
self.posts(allPosts);
You don't need the model to have ko.observable if you're just displaying them. If you want to edit model as well, then leave as.
Also, I tend to do this for single or multiple view models:
ko.applyBindings({viewModel : new viewModel() };
This allows for having multiple named view models. Access scope using: $root.viewModel
This is what I did earlier: http://jsfiddle.net/jFb3X/
Check your code against this fiddle then.
Script tags also need to be above the closing body tags
<html>
<head>
</head>
<body>
<!-- all your html content -->
<script type="text/javascript">
var viewModel = function () {
}
ko.applyBindings({viewModel : new viewModel()});
</script>
</body>
</html>
Is it something as simple as waiting for the DOM to be ready?
Are you able to try the following:
$(function () {
ko.applyBindings(postlistviewmodel);
});
Source: I've done this a few times and been stumped for a bit trying to see what I did wrong. :-)
(As a style thing, I'd also move the /body to after the /script - probably not related to your issue though).
I suspect you get multiple posts from /posts. You only push a single item (array).
...
$.getJSON("/posts", function(getPost){
var mappedPosts = $.map(getPost, function(item){
return new Post(item)
});
for(var i = 0; i < mappedPosts.length; i++) {
self.posts.push(mappedPosts[i]);
}
});
...
I have been trying to pass a model object to be evaluated in my template but had no luck. I tried the following but had no luck
dashboardmodel.js
var myMod = Backbone.Model.extend({
defaults: {
name: "mo",
age: "10"
}
});
myview.js
var dashView = Backbone.View.extend({
el: '.content-area',
this.mymodel = new myMod({}),
template: _.template(dashBoardTemplate, this.mymodel),
initialize: function() {
},
render: function() {
this.$el.html(this.template);
return this;
}
// more javascript code.............
dahboard.html
<p> Hello <%= name %> </p>
PS: I am using the underscore template engine
In addition , your way to pass a model to a view is not flexible, because you would pass an instance of your model, instead of a default model. Thus, you might want to single out
this.mymodel = new myMod({}),
(btw, above line gives me error message in my chrome browser because of "=" sign)
Then, suppose you have an instance A:
A = new myMod({"name": "World", "age":100})
Then pass it to your view as:
myview = new dashView({mymodel: A})
One more step, you have to do is to call render function:
myview.render();
Here's a complete solution:
<html>
<script src="jquery-1.10.2.min.js"></script>
<script src="underscore-min.js"></script>
<script src="backbone.js"></script>
<body>
<script type="text/template" id="dashBoardTemplate">
<p> Hello <%= name %> </p>
</script>
<div class="content-area">
</div>
<script type="text/javascript">
var myMod = Backbone.Model.extend({
defaults: {
name: "mo",
age: "10"
}
});
var dashView = Backbone.View.extend({
el: '.content-area',
template: _.template($("#dashBoardTemplate").html()),
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
mymod = new myMod({"name": "World", "age":100});
myview = new dashView({model:mymod});
myview.render();
</script>
</body>
</html>
If you want to study backone.js, please read this open source book which get me started:
http://addyosmani.github.io/backbone-fundamentals/
You need to get properties of a Backbone Model with the getter syntax, so you need to rewrite your template to:
<p> Hello <%= obj.get('name') %> </p>
Or you need to convert your model into a plain JS object when calling _.template what you can do with the .toJSON() (which creates a clone of the model) or .attributes property:
template: _.template(dashBoardTemplate, this.mymodel.toJSON())
Side note: you should consider to move the template rendering logic into your view. Because your current code render your template when your view is declared and not when you call the render method. So you might get unexpected result. So your code you look like this:
template: _.template(dashBoardTemplate), //only compile the template
render: function() {
this.$el.html(this.template(this.mymodel.toJSON()));
return this;
}
my first post on stackoverflow. (and english is not my native tongue).
I am trying to learn how to use emberjs.
It's not easy because of the lack of good tutorials.
So I decided to code a chat, I use nodejs and socket.io server-side.
Html
<script type="text/x-handlebars">
<div class="page">
<div class="users">
</div>
<div class="messagebox">
{{#view App.TextField valueBinding="currentMsg" placeholder="your message"}}{{/view}}
<button {{action "sendMsg"}}>Send</button>
</div>
<div id="chatbox">
{{#collection contentBinding="App.MsgsController" tagName="ul"}}
<b>{{value}}</b>
{{/collection}}
</div>
</div>
</script>
Javascript
var id;
var socketio = io.connect("127.0.0.1:8888");
socketio.on('id', function (data) {
id = data;
});
socketio.on("broadcast", function (data) {
if (id == data.id) {
return
}
App.MsgsController.addMsg(data.message);
});
socketio.on("own", function (data) {
App.MsgsController.addMsg(data.message);
});
App = Ember.Application.create();
App.Msg = Ember.Object.extend({
value: null
});
App.MsgsController = Ember.ArrayController.create({
content: [],
addMsg: function (value) {
var msg = App.Msg.create({
value: value
});
this.pushObject(msg);
}
});
App.TextField = Ember.TextField.extend({
insertNewline: function() {
this.get("controller").send("sendMsg");
}
});
App.ApplicationController = Ember.Controller.extend({
currentMsg: 't',
sendMsg: function () {
var currentMsg = this.get('currentMsg');
if(currentMsg) {
socketio.emit("message", { message: currentMsg, id: id});
this.set('currentMsg', '');
}
}
});
I want to focus App.TextField after the App.ApplicationController.sendMsg call.
I tried
App.TextField.$().focus()
but it seems that I can only use $() inside of its methods.
Someone can help me, please?
Edit :
Ok, I found the answer.
App.TextField is like "class", and the one on the view is an instance.
I must add an id in my view
{{#view App.TextField valueBinding="currentMsg" placeholder="your message" id="mytextfield"}}{{/view}}
and use jquery selector to access to the instance
$('#mytextfield').focus();
Use didInsertElement hook for the view to handle jquery methods.
http://emberjs.com/api/classes/Ember.View.html#event_didInsertElement