how can I call the (ko.observableArray) from (init) JSON function? - javascript

Well the title is confusing so I'll give you my code to understand my problem
in knockout tutorials they use functions instead of JSON I mean like this:
data = [
{
id: 1,
name: 'somehing'
},{
id: 2,
name: 'somehing else'
},
]
here is my problem
var ViewModel = function () {
var self = this;
self.dataList = ko.observableArray(data);
console.log(ViewModel.dataList);
};
while on other websites and most of tutorials and projects in github uses JSON
var ViewModel = {
dataList : ko.observableArray(data),
init: function() {
console.log(ViewModel.dataList);
}
};
this line
dataList : ko.observableArray(data),
when I try to call dataList it return this
function d(){if(0<arguments.length)return d.Wa(c,arguments[0])&&(d.X(),c=arguments[0],d.W()),this;a.k.Ob(d);return c}
and If I try to get its value console will tell me that dataList is not defined
but if I pass data directly to dataList like this (Which is not observableArray anymore) it will give me the full objects values in console
dataList : dataList,
the return value in console
[Object, Object]
how can I call the ko.observableArray from init function?
I want to follow the tutorials on the web like this one but my issue is the same.
http://opensoul.org/2011/06/23/live-search-with-knockoutjs/
Actually it's not only ko.observableArray arrays also I cannot call ko.observable objects

when I try to call dataList it return this
Your code doesn't call ViewModel.dataList, it just accesses it, which gives you the function (remember observables are functions). To call it, add ():
console.log(ViewModel.dataList());
// Note ----------------------^^

Related

JavaScript knockoutjs, set nested object value doesn't update Html?

I'm using knockout 3.3.0. Assume I have a model as the following:
As you can see There are two nested objects, DeviceStatistics and Product.
At first they are OK and work fine and update HTML.
I assign the new values to these objects as the following:
window.KoEntityModel.EntityModel.DeviceStatistics = ko.mapping.fromJS(newJsonModel);
It's OK without any problems, but knockout doesn't update(change) HTML
Whereas, chrome console shows window.KoEntityModel.EntityModel.DeviceStatistics is observable:
How can I fix it?
well to convert object into function you need to do something like below
viewModel:
var fromserver = {
'device': {
'one': 'onevalue'
},
'product': {
'prod': 'prodone'
},
'name': 'supercool'
};
var ViewModel = function() {
var self = this;
self.device = ko.observable();
self.prod = ko.observable();
ko.mapping.fromJS(fromserver, {}, self); //this converts object into function & keeps the other prop's coming from server intact .
};
var vm = new ViewModel();
ko.applyBindings(vm);
working sample fiddle here shows the modified data .
I found the solution,
We have to update a knockoutJs view model with the following code:
ko.mapping.fromJS(newDataInJson, {}, knocoutJsViewModel);

Pushing into JSON suddenly not working

I'm a beginner in AngularJS, and I have a problem with pushing into an array inside a JSON. (I hope I'm using the correct terminology)
//I have a JSON that looks like this
var items = [
{name:[
{names: 'John', msg:[""]}, {names: 'Dolly', msg:[""]}
]}
];
Below code is inside a Controller:
$rootScope.items = People.list();
$rootScope.name = "John";
for(var i=0;i<$rootScope.items.name.length;i++)
{
if (name== $rootScope.items.name[i].names)
{
People.addcomment(user.comment,i);
}
}
Below code is in my service called 'People':
this.addcomment = function(comment,x) {
items[0].name[x].msg.push(comment);
}
this.list = function () {
return items[0];
}
The JSON is declared in the service. The HTML code is as below:
<textarea placeholder="Enter comment" ng-model="user.comment"></textarea>
<button ng-repeat = "x in items.name" ng-if="name==x.names"
ng-click="addcomment(user,name)">Submit</button>
Now, my problem is that on clicking the 'Submit' button, the 'message' I have typed in the teaxtarea is not getting stored in the 'msg' array corresponding to "John" (inside of the JSON). What is going wrong?
I had the entire code of the Service inside of the Controller earlier, and the code used to work properly then. I suppose I must have done some mistake with the arguments I'm passing to the function in the service.
Could someone please help me out?
So the workflow of you app is as follows:
Service is instantiated, JSON is stored in the scope of your service
Controller is instantiated, copies the array from People.List() to rootScope.items
The ng-repeats repeats for each Element in the rooScope.items - NOT for each Element in the items array in your People-service
Someone enters a new message
This message is added to items in your service with People.addComment.
Step number 5 only changes the items in your service, NOT the items in your rootScope. That's why the ng-repeat doesn't add a new Element.
To keep those two scopes in sync, add a function to your controller:
function updateList() {
$rootScope.items = People.list();
}
Call this method after you call People.addComment().
Lastly, maybe this is just an opinion, you should change your JSON-structure. In gets ways clearer if you set up your data like this:
var items = [
{name: 'John', msg:[]},
{name: 'Dolly', msg:[]}
];
Now you have an array of objects. Your People.list() function now returns items and you can add a new Person by calling items.push({name: 'Judith', msg:[]}); and you can add a message with items[i].msg.push("This is a new message");

Ember not updating template when I add or remove an object from an array field in the model

So I've got a model that has a field of an array objects it looks like this
App.Post = DS.Model.extend({
...
codes: attr(),
...
});
and Codes looks like this
codes: [
{
code: stuff
comment: stuff_1
other_things: other_stuff
},
{
...
},
{
...
}
...
]
So now I have an add / remove button which has actions attached to them and this is what they do
add_code_input: function() {
var codes = this.get('model.codes');
var self = this;
var last_code = codes[codes.length-1];
// Cannot edit as an ember.set error is occurring
last_code.code = 'Add new (please change)';
last_code.code_type = "";
last_code.comment = "";
console.log(last_code);
codes.push(last_code);
this.set('model.codes', codes);
console.log(codes);
},
remove_code_input: function() {
var codes = this.get('model.codes');
codes.pop();
console.log(codes);
this.set('model.codes', codes);
}
So the remove works fine but the add doesn't work.
It gives me this error when I try to update last_code: Uncaught Error: Assertion Failed: You must use Ember.set() to access this property (of [object Object])
I essentially want to add a dummy object that user can change.
So first issue is figuring out how to add dummy objects into the array properly and secondly how to update the template as the model changes.
You should be using arr.pushObject(obj) and arr.popObject() for manipulating an array in Ember (think of it as the setter/getter of arrays).
is codes really just attr() because it appears to be behaving like a DS record.
If it is a record, you just use record.set('foo', 'bar') if it's just a POJO you can use Ember.set(obj, 'foo', 'bar').
It should be as easy as this (I'm assuming you're using and in the ObjectController here)
var newCode = {
code:'foo'
};
this.get('codes').pushObject(newCode);

Why is my controller property 'undefined' when I assign it the result of $resource query()?

I have a JSON data structure:
[
{
"title" :"a1",
"id" :"b1",
"name" :"c1"
},
{
"title" :"a2",
"id" :"b2",
"name" :"c2"
}
]
I am accessing is as an external JSON and parsed through a factory method. I want it to assign it to a Javascript variable in my controller.
function Control($scope,data)
{
var e=data.query(); /* getting the external JSON data */
alert(e[0].title);
}
It says that e[0] is undefined. Is there any other way I can assign it to a Javascript variable and then traverse through it? Please help.
Most likely, #Marty is correct. If you are using the query() method from the $resource service, it is asynchronous. This will likely do what you want:
data.query( function( data ) {
var e = data;
alert(e[0].title);
});
Okay, so $resource can be confusing like this... It immediately gives you a reference to the return object, but doesn't update the object until the asynchronous AJAX call returns... so...
If you put your return value from data.query() in a property on $scope, since it's $watched when you bind it in your view, you'll see it update. HOWEVER, if you're just trying to alert it, it will alert the value before it's been updated.. again because of the async aspect of $resource.
Otherwise, you can get the value the way that #MarkRajcok has shown in his answer.
Here is a psuedo-code illustration of ways you can use $resource query();
app.controller('FooCtrl', function($scope, $resource) {
var Bar = $resource('/Bar/:id', {id: '#id'});
// here, we get the result reference and stick it in the scope,
// relying on a digest to update the value on our screen.
$scope.data = Bar.query();
//OR
//here we already have a reference.
var test = Bar.query(function() {
//in here, test has been populated.
$scope.data2 = test;
});
alert(test); //not populated here, yet.
//OR
Bar.query(function(x) {
$scope.data3 = x;
});
});
This is all done so the object(s) returned can have functions pre-instantiated on them like $save(), etc.

How to rebind variable assignments

I am currently attempting to build my own JS framework as a way to learn. I have created a method for making an new model like so:
var myModel = new $n.model.make({
data: {
id: _contentID,
name: $('#frm_content_name').val()
},
route: '/my/path',
callback: function(){}
});
The make() function is simple:
$n.model.make = function(obj){
var self = this;
self.data = obj.data;
self.route = obj.route;
self.callback = obj.callback;
}
As you can see, the name parameter is assigned to a form input field's value. If I change this input field value on the UI, the name parameter is still assigned to the original value of the input field so if I try to save the data to the DB, nothing has changed.
Once I have established my model, what is a good way to "rebind" the data parameters to their assigned form fields to get the latest information?
As mentioned in a comment you could do this:
data: {
id: _contentID,
name: function() {
return $('#frm_content_name').val();
}
},
Calling data.name() would always fetch the latest information. Another way is this:
data {
id: _contentID,
name: $('#frm_content_name')
},
Now you would need to call data.name.val(); personally I don't really like this because of the missing encapsulation.
I found the answer I was looking for - two-way data binding. Here is the tutorial I used to solve my issue: http://www.lucaongaro.eu/blog/2012/12/02/easy-two-way-data-binding-in-javascript/

Categories