One little problem which JSONStore.add(data).then().fail()
The function initialiserBD() runs and returns success. The function remplireBD() doesn't return success. Surely, it is the function WL.JSONStore.get().add().then().fail()
Object "errorObject" send error :-50 PERSISTENT_STORE_NOT_OPEN
function wlCommonInit() {
initialiserBD();
remplireBD();
}
function initialiserBD() {
var collectionName="Personnes" ;
var collections = {};
collections[collectionName]= {};
collections[collectionName].searchFields={nom :'string'};
WL.JSONStore.init(collections).then(function(){})
.fail(function(errorObject) {
alert(errorObject.tostring());
});
}
function remplireBD(){
var data = {
nom :'Bill Gates'
};
var collectionName = 'Personnes';
WL.JSONStore.get(collectionName).add(data).then(function () {})
.fail(function (errorObject) {
alert(errorObject.toString());
});
}
I think your problem is two-fold...
You initialize the collection both before init and "after" init (var collectionName="Personnes" ;)
JavaScript is async, and you're calling initialiserBD and remplireBD one after the other instead of calling remplireBD in the success callback of initialiserBD, which could lead to trying to .get() before init() completed...
Related
Is there any kind of wildcard operator in the Durandal observable plugin, as there is in (for example) JsObservable?
The Durandal observable documentation gives this example:
var observable = require('plugins/observable');
var viewModel:{
firstName:'',
lastName:''
};
observable(viewModel, 'firstName').subscribe(function(value){
console.log('First name changed.');
});
viewModel.firstName = 'Test';
What I'd like to do is use a wildcard to subscribe to any changed property on the target. Something like this:
observable(viewModel, '*').subscribe(function(property, value){
console.log(property + ' changed.');
});
I don't see anything in the API documentation, but wondered if there was anything undocumented, or if anyone has a workaround to implement this behaviour.
Unfortunately, there is no wildcard operator for this functionality.
But you can easily create wrapper module for this functionality.
Here is small example:
var observable = require('plugins/observable');
var wildcardObservable = function(obj, changeCallback){
for(var prop in obj){
observable(obj, prop).subscribe(changeCallback);
}
}
var changeCallback = function() {
console.log('property changed.');
}
Usage:
var viewModel:{
firstName:'',
lastName:''
};
wildcardObservable(viewModel, changeCallback);
With thanks to U10 for the start above, (and with reference to a few examples on the web) I came up with the following, which uses a closure to track all the necessary properties. It's a bit messy but it does what I need for now - hopefully it will be of use to someone.
var ChangeTracker = (function () {
function ChangeTracker() {
}
ChangeTracker.prototype._trackChange = function (prop, target) {
var type = typeof (target[prop]);
var value = target[prop];
_logger.log("_trackChange", { target: target, prop: prop, type: type, value: value }, "CT");
_obs(target, prop).subscribe(function (newValue) {
var obj = {
target: target,
prop: prop,
newValue: newValue,
oldValue: value
};
_logger.log(">>>>>>>>>>>>>>> CHANGE!", obj, "CT");
value = newValue;
});
};
ChangeTracker.prototype.TrackChanges = function (target) {
var _this = this;
for (var prop in target) {
if (target.hasOwnProperty(prop)) {
this._trackChange(prop, target);
}
var underlying = ko.utils.unwrapObservable(target[prop]);
if (underlying instanceof Array) {
ko.utils.arrayForEach(underlying, function (item) {
_this.TrackChanges(item);
});
} else if (typeof underlying === "object") {
this.TrackChanges(underlying);
}
}
}
};
return ChangeTracker;
})();
how can i get it work ?
define(['plugins/router', 'knockout', 'services/logger', 'durandal/app', 'mapping', 'services/routeconfig', 'services/dataBindingHandlers'], function (router, ko, logger, app, mapping, routeconfig, dataBindingHandlers) {
//#region Internal Methods
function activate() {
logger.log('Übersicht View Activated', null, 'newSearch', true);
return true;
}
//#endregion
//==jquery=================================================
function attached() {
}//-->end of attached()
var url = "https://www.googleapis.com/books/v1/volumes?q=the+Cat+In+The+Hat", path = $.getJSON(url);
path.then(function (data) {
console.log(data.items);
var viewModel = {
title: 'Overview',
query: ko.observable('')
};
viewModel.activate = activate();
viewModel.attached = attached();
viewModel.model = mapping.fromJS(data.items, {}, viewModel);
/*understanding ko.mapping.fromJS signature:knockoutjs.com/documentation/plugins-mapping.html
ko.mapping.fromJS(data) - this syntax will create view model.
ko.mapping.fromJS(data, mappingOptions) - this will create view model with particular options.
ko.mapping.fromJS(data, mappingOptions, viewModel) -
ko.mapping.fromJS(data, viewModel) -
ko.mapping.fromJS(data, {}, viewModel) - and this one convers your data without mapping options and put it to view model.
*/
viewModel.filteredItems = ko.computed(function () {
var search = this.query().toLowerCase();
alert("i'am here in viewModel.books computed");
console.log(viewModel.model);
return ko.utils.arrayFilter(this.model(), function (book) {
return book.id().toLowerCase().indexOf(search) >= 0 || book.kind().toLowerCase().indexOf(search) >= 0 || book.etag().toLowerCase().indexOf(search) >= 0
});
}, viewModel);
return viewModel;
});
});
Utility Functions in KnockoutJS
UPDATES: i recieve a loop of objects when i console.log(viewModel.model);
You haven't clearly stated what it is that doesn't work about it?
However, you probably need to add the activate and attached methods to the viewModel in order for them to be called by durandal.
viewModel.activate = activate;
viewModel.attached = attached;
You probably also intend this chunk of code to be called within the activate function and not in the define call:
var url = "https://www.googleapis.com/books/v1/volumes?q=the+Cat+In+The+Hat",path =$.getJSON(url);
path.then( function (data) {
var books = data.items;
console.log(books);
I am trying to figure out how to use a custom view location strategy, I have read the documentation at this page http://durandaljs.com/documentation/Using-Composition/ but I don't exactly understand what the strategy function should look like.
Can anybody give me a quick example of what the implementation of this function would be like and the promise that returns (even a simple one) etc?
Thanks in advance,
Gary
p.s. This is the code in my html:
<div>
<div data-bind="compose: {model: 'viewmodels/childRouter/first/simpleModel', strategy:
'viewmodels/childRouter/first/myCustomViewStrategy'}"></div> </div>
and this is the code in my myCustomViewStrategy:
define(function () {
var myCustomViewStrategy = function () {
var deferred = $.Deferred();
deferred.done(function () { console.log('done'); return 'simpleModelView'; });
deferred.fail(function () { console.log('error'); });
setTimeout(function () { deferred.resolve('done'); }, 5000);
return deferred.promise();
};
return myCustomViewStrategy;
});
but I get the error:
Uncaught TypeError: Cannot read property 'display' of undefined - this is after done has been logged in the console window.
Okay I solved this by creating my custom view strategy by the following:
define(['durandal/system', 'durandal/viewEngine'], function (system, viewEngine) {
var myCustomViewStrategy = function () {
return viewEngine.createView('views/childRouter/first/sModelView');
}
return myCustomViewStrategy;
});
As I found the documentation a bit lacking on compose binding's strategy setting I checked the source code how it works. To summ it up:
The module specified by the compose binding's strategy setting by its moduleId
must return a function named 'strategy'
which returns a promise which results in the view to be bound
as a HTML element object.
As a parameter the strategy method receives the compose binding's settings object
with the model object already resolved.
A working example:
define(['durandal/system', 'durandal/viewEngine'], function (system, viewEngine) {
var strategy = function(settings){
var viewid = null;
if(settings.model){
// replaces model's module id's last segment ('/viewmodel') with '/view'
viewid = settings.model.__moduleId__.replace(/\/[^\/]*$/, '/view');
}
return viewEngine.createView(viewid);
};
return strategy;
});
Durandal's source:
// composition.js:485
for (var attrName in settings) {
if (ko.utils.arrayIndexOf(bindableSettings, attrName) != -1) {
/*
* strategy is unwrapped
*/
settings[attrName] = ko.utils.unwrapObservable(settings[attrName]);
} else {
settings[attrName] = settings[attrName];
}
}
// composition.js:523
if (system.isString(context.strategy)) {
/*
* strategy is loaded
*/
system.acquire(context.strategy).then(function (strategy) {
context.strategy = strategy;
composition.executeStrategy(context);
}).fail(function(err){
system.error('Failed to load view strategy (' + context.strategy + '). Details: ' + err.message);
});
} else {
this.executeStrategy(context);
}
// composition.js:501
executeStrategy: function (context) {
/*
* strategy is executed
* expected to be a promise
* which returns the view to be bound and inserted to the DOM
*/
context.strategy(context).then(function (child) {
composition.bindAndShow(child, context);
});
}
In my Knockout view model I have a Save() function which sends a jQuery POST request. Inside this POST request is a call to ko.toJS(this).
Whenever I call this Save function the browser becomes unresponsive and eventually tells me that there's too much recursion. Upon debugging (by using breakpoints), I found that when I call toJS() it appears to do some degree of cloning of the object, and in doing this cloning it calls the Save() function, which in turn calls toJS()... and there's the recursion.
Why exactly does this happen, and is there a way to avoid it without using toJSON()?
[I have another question regarding toJSON, and which explains why I don't want to use it.]
For the sake of completeness, here is my view model.
function vmDictionary(dict) {
if (dict === null || dict === undefined) {
return;
}
var self = this;
// directly-assigned variables
self.Concepts = new vmConcepts(dict.Concepts);
self.Deleted = ko.observable(dict.Deleted);
self.Description = ko.observable(dict.Description);
self.IncludeInSearch = ko.observable(true);
self.ID = ko.observable(dict.ID);
self.Languages = ko.observableArray(dict.Languages);
self.LastUpdate = new vmChangeRecord(dict.LastUpdate);
self.Name = ko.observable(dict.Name);
self.Public = ko.observable(dict.Public);
self.TemplateName = function(observable, bindingContext) {
return "dictionary-template";
};
// computed variables
self.PublicText = ko.computed(function() {
return sp.Utils.Localize(self.Public
? "Public"
: "Private");
});
// exposed functions
self.Save = function () {
$.ajax({
data: ko.toJSON(self),
dataType: "json",
type: "POST",
url: [...],
statusCode: {
200: function (response) {
console.log(response);
}
},
error: function (xmlHttpRequest, textStatus, errorThrown) {
console.log(xmlHttpRequest);
console.log(textStatus);
console.log(errorThrown);
}
});
};
}
UPDATE: added the entire view model (above).
You must be doing something wrong, works in a little fiddle for me
http://jsfiddle.net/brN9s/
ViewModel = function() {
this.someData = ko.observable("Test");
this.dto = ko.observable();
};
ViewModel.prototype = {
Save: function() {
this.dto(ko.toJS(this));
}
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
viewModel.Save();
I want to migrate the javascript in my site from YU2 to YUI3, but I am only a poor amateur programer and I am stuck at the first pitfall.
I have the following code:
MyApp.Core = function() {
return {
init: function(e, MyAppConfig) {
if (MyAppConfig.tabpanels) {
MyApp.Core.prepareTabpanels(MyAppConfig.tabpanels);
}
},
prepareTabpanels: function(tabpanels) {
// Code here
}
}
}();
var MyAppConfig = {
"tabpanels":{"ids":["navigation"]}
};
YAHOO.util.Event.addListener(window, "load", MyApp.Core.init, MyAppConfig);
How can I pass the MyAppConfig object to the MyApp.Core.init function by using YUI3 "domready" event listener?
Thanks in advance!
You should be able to do something like:
var MyApp = {};
MyApp.Core = function(){ return {
init: function(MyAppConfig) {
console.log(MyAppConfig);
},
prepareTabpanels: function(tabpanels) {
// Code here
}
}
}();
var MyAppConfig = {
"tabpanels":{"ids":["navigation"]}
};
YUI().use('node', 'event', function(Y){
Y.on('domready', MyApp.Core.init, this, MyAppConfig);
});
Note that the event is not passed in as the first parameter, it is the config.
Y.on accepts parameters as <event_type>, <callback_function>, <context>, <params>..
any parameter after the third item is passed through to the callback function so MyAppConfig becomes the first parameter in your init.
EDIT
See the YUI3 API documentation here: http://developer.yahoo.com/yui/3/api/YUI.html#method_on