Updating Knockout viewModel - javascript

I'm attempting to update a knockout view model, but each time I try to push to an observable array it gives me an error that AuditViewModel is undefined.
function (data, update) {
if (update == false) {
var AuditViewModel = {
auditEvents: ko.observableArray(data.requirements)
};
ko.applyBindings(AuditViewModel);
} else {
AuditViewModel.auditEvents.push(data.requirements);
}
}
On the page load this function always runs with update == false, and that originally populates the view model. When I later call with update ==true then it fails. Can someone point me in the right direction?

Note that the line var AuditViewModel = { ... } is only executed if update == false. Because AuditViewModel is a local variable, if you later call the function when update == true, AuditViewModel will be undefined.
You will need to store the view model elsewhere, ie: window.AuditViewModel = { ... }.
Example:
function (data, update) {
if (update == false) {
window.AuditViewModel = {
auditEvents: ko.observableArray(data.requirements)
};
ko.applyBindings(window.AuditViewModel);
} else {
window.AuditViewModel.auditEvents.push(data.requirements);
}
}

Related

Compare a parameter value returned in JSON

The code return data in JSON format and it contains around ten values, one of the value called state. I want to create function to compare a returned value of state only, for example if state = one show image1 and if state = 2 show image2. How to do that?
JQuery url
var RealDataApi = function () {
var url_getgatedata = "api/realdata/getgatedata";
// public functions
return {
getGateData: function (done, fail, always) {
var jqxhr = $.get(url_getgatedata);
jqXhrHandler(jqxhr, done, fail, always);
},
JSON Data:
{"gateNo":1,"fullOpen":false,"fullClose":false,"opening":false,"closing":false,"mode":null,"state":null,"cond":null,"positionM":null,"positionP":null}
FIDDLE
getParameterByName(data);//get parameter name state
function getParameterByName(data) {
if (data.state == '2') {
alert('2');
} else {
alert(data.state);
}
}
Named the json data then you can get the value of state like data.state then compare it to which ever value you want to compare
Use eval on a json response:
function getState(data)
{
if(data.state==1)
return "image1";
else if(data.state==2)
return "image2";
}
var jqxhr=eval({"gateNo":1,"fullOpen":false,"fullClose":false,"opening":false,"closing":false,"mode":null,"state":1,"cond":null,"positionM":null,"positionP":null});//parse as js object or eval($.get(url_getgatedata));
alert(getState(jqxhr));
Please try this:
if (jqxhr.state == 1) {
//Do whatever you wanna do...
} else if (jqxhr.state == 2) {
//Do whatever you wanna do...
}

$digest error on $watch for changes in model

My application receive updates on items via SSE (server sent events) from the API.
What I have is a main controller that looks for this changes:
if (!!window.EventSource) {
var source = new EventSource('/items/updates');
} else {
console.log('SSE not supported');
}
source.addEventListener('items', function (e) {
var data = JSON.parse(e.data);
Items.updateOneItem(data);
$scope.$digest();
}, false);
Items is a service factory that handle the changes:
App.factory('Items', function () {
var items = {};
// previous and updated item
var previousItemState = null;
var updatedItem = null;
items.list = [];
items.getUpdatedItem = function () {
return {
previous: previousItemState,
updated: updatedItem
};
};
items.updateOneItem = function (item) {
var i = $.map(items.list, function (e, i) {
if (e !== null) {
if (e.id === item.id) {
return i;
}
}
});
previousItemState = items.list[i];
items.list[i] = item;
updatedItem = item;
};
return items;
});
Basically in this service I store the items and I'm trying to check if an item has been updated and what exactly is changed in the item model.
In my controller I'm watching this and doing my controls, or maybe I'm trying to do that:
$scope.$watch(Items.getUpdatedItem, function (item) {
if (item.previous !== null && item.updated !== null) {
// do my controls on previous and updated item...
}
});
What happen is that I have an error like this:
Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting! [...]
I tried, from my Items service, to return just a single value and it works fine but I receive just the updated item and I don't know how to check in what the item is changed:
items.getUpdatedItem = function () {
return updatedItem;
};
My questions are:
Why I can not return an object from my service method?
What is in this case the best practice to have the previous and updated item in order to see changes?
Cheers
Firstly, you are not supposed to run $digest() manually. Wrap the code you need to digest in $timeout.
Second thing, it is correct to pass your object like this:
items.getUpdatedItem = function () {
return updatedItem;
};
Problem you are having with accessing old and new version in $watch is easily solved. Second parameter you are passing to $watch is a function that actually use two arguments:
$scope.$watch(Items.getUpdatedItem, function (newItem, oldItem) {
if (oldItem !== newItem) {
// do my controls on previous and updated item...
}
});

Sencha: Cannot call method 'getHeader' of undefined

I am try to update the record of a dataview.List from with the data modified from it's associate form.Panel
code:
onListItemTap:function(list,index,target,record,e){
this.getMain().push({
xtype:'userform',
title:record.data.name,
record:record,
listeners:{
hide:function(form){
record.setData(form.getValues());
list.refresh();
}
}
});
},
Code after record.setData(...);list.refresh();
page getting error:
Uncaught TypeError: Cannot call method 'getHeader' of undefined
It seems like there are issue with the sencha touch 2.3.1 that I am using.
I simply comment the grouped=true property in List component. It works.
code:
{
xtype:'list',
id:'list-user',
store:'Users',
itemTpl: new Ext.XTemplate(...),
flex:1,
//grouped:true
}
hope this finding will save time and from frustration for you.
The problem is the method updateHeaderMap List component.
Ext.define('Nerine.override.List', {
override:'Ext.dataview.List',
updateHeaderMap: function() {
var me = this,
headerMap = me.headerMap,
headerIndices = me.headerIndices,
header, i, item;
headerMap.length = 0;
for (i in headerIndices) {
if (headerIndices.hasOwnProperty(i)) {
/* fix bug */
// console.log('aaa', me.getItemAt(i)); return null
// console.log('bbb', me.getItemAt(i).getHeader());
if( !(item = me.getItemAt(i))) {
continue;
}
header = me.getItemAt(i).getHeader();
headerMap.push(header.renderElement.dom.offsetTop);
}
}
}
});
The group headers have no records in the store. This override solves the issue by checking whether the record for which scrollToRecord is called really is in the store. Furthermore it solves the issue that when calling scrollToRecord is done in painted event, it is possible that the headerMap is not yet ready, which means that the pinnedHeader is not correctly updated when using scrollToRecord.
Ext.define("MyApp.override.List", {
override:'Ext.dataview.List',
scrollToRecord: function(record, animate, overscroll) {
var me = this,
store = me.getStore(),
index = store.indexOf(record);
if(index>-1 && index < this.listItems.length) {
this.updateHeaderMap();
this.callOverridden(arguments);
}
}
});

how to run a function with parameters

I have a function that simply validates forms (for old browsers). The function works just fine except that I have to pass the parameters every time I call this function, where in fact I already specified the default parameters in 'config'.
So by logic, If I called the function as: validateMe(); it should run as validateMe({requiredClass: '.required', verifiedClass: 'invalid'});
but unfortunately calling the function without parameters doesn't work correctly ( in my case the form triggers the submission event) (it doesn't reach return false).
so what is missing in the code to run the function with the default settings??
function validateMe(vform, settings) {
var vform, //form name or id
config = {
'requiredClass': '.required',
'verifiedClass': 'invalid'
};
if (settings) {
$.extend(config, settings);
}
$(vform).on('submit', function(){
var inputs = $(this).find(config.requiredClass),
required = [];
for (i=0; i < inputs.length; i++) {
if (inputs[i] != null) {
if ($(inputs[i]).val().replace(/^\s+|\s+$/g, '') == '') {
required.push($(inputs[i]).index());
}
}
}
if (required.length > 0) {
$(this).find('input').removeClass(config.verifiedClass);
for(n=0;n<required.length;n++) {
$(inputs[n]).addClass(config.verifiedClass);
}
return false;
}
});
}
Any help?
Thanks.
function validateMe(vform, settings) {
this.vform = vform || 'default',
this.setting = 'whatever',
this.private = ''
}
var newInstance = new validateMe();
now you have an instance of it, so you can define it as you go.

document.write in function body

I have the following JavaScript function which receives coordinates and returns the nearest tube station:
function coord() {
var metro = new YMaps.Metro.Closest(new YMaps.GeoPoint(<?=getCoords($addr) ?>), { results : 1 } )
YMaps.Events.observe(metro, metro.Events.Load, function (metro) {
if (metro.length()) {
metro.setStyle("default#greenSmallPoint");
var firstStation = metro.get(0);
var tubest = (firstStation.text).split("метро ");
var tube = tubest[1];
if($("span#tubest").text() == '') {
$('.whiteover').hide();
}
} else {
if($("span#tubest").text() == '') {
$('.whiteover').hide();
}
}
});
}
The value which I need to output as a result of this function execution is the value of the "tube" variable (var tube = tubest[1];). Basically a simple document.write will work. Or a simple return value like:
var tubestation = coord();
However I'm not sure how to achieve this.
You can't have this function return the value, since you're using an observer pattern - which sets up an asynchronous logic to the code. Simply saying, at the time that your coord() function returns, the value is not there yet.
To deal with this, normally you would pass a callback function, then resume your computation there.
Declare your function as:
function coord(callback)
then, after you know the value you want, call the callback with the value:
callback.call(null, tube);
Do it after your if { ... } else { ... } so your callback gets called both on success and on failure (on failure it will pass undefined, you might want to correct it by declaring var tube = null before the if).
then, instead of:
tubestation = coord();
call it like this:
coord(function(tubestation) {
// continuation of your code here
});
You probably won't be able to use document.write since the time to use it would be long past, but you can set the value as the contents of an element that you already generated. You have jQuery in your tags, so it's quite easy:
coord(function(tubestation) {
$('#tube_station').text(tubestation);
});
assuming you have <div id="tube_station"/> somewhere in your HTML.
How about this simple add to that function?
function coord() {
var metro = new YMaps.Metro.Closest(new YMaps.GeoPoint(<?=getCoords($addr) ?>), { results : 1 } )
YMaps.Events.observe(metro, metro.Events.Load, function (metro) {
if (metro.length()) {
metro.setStyle("default#greenSmallPoint");
var firstStation = metro.get(0);
var tubest = (firstStation.text).split("метро ");
var tube = tubest[1];
$('div#myDivResult').html(tube)
if($("span#tubest").text() == '') {
$('.whiteover').hide();
}
} else {
if($("span#tubest").text() == '') {
$('.whiteover').hide();
}
}
});
}

Categories