Uncaught TypeError: Object #<Object> has no method 'navigateTo'? - durandal

I created a project using hottowel 2.0.1 in VS 2012 and have the following code following the HotTowel course/example. However I got following error.
Uncaught TypeError: Object # has no method 'navigateTo' ?
I set a break point at the line and found router doesn't have method navigateTo. However, it does have method navigate. Is the name changed?
define(['services/datacontext', 'plugins/router', 'services/logger'],
function (datacontext, router, logger) {
......
var gotoDetails = function (selectedEvent) {
if (selectedEvent && selectedEvent.Id()) {
var url = '#/eventdetail/' + selectedEvent.Id();
router.navigateTo(url);
}
};
var viewAttached = function (view) {
bindEventToList(view, '.event-brief', gotoDetails);
};
var bindEventToList = function (rootSelector, selector, callback, eventName) {
var eName = eventName || 'click';
$(rootSelector).on(eName, selector, function () {
var event = ko.dataFor(this);
callback(event);
return false;
});
};
//#endregion
var vm = {
activate: activate,
deactivate: deactivate,
refresh: refresh,
events: events,
title: title,
attached: viewAttached
};
return vm;
});

You should convert your application to Durandal 2:
http://www.johnpapa.net/upgrading-durandal-to-version-2-0/
(amongst other changes there is this: router.navigateTo is now router.navigate)
or use official Durandal 2 template instead of HotTowel

Related

JSONStrore / WORKLIGHT

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...

knockout search issue Property 'model' of object #<Object> is not a function

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);

Durandal Custom View Location Strategy

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);
});
}

Durandal, get path of the current module

Is there a way in Durandal to get the path of the current module? I'm building a dashboard inside of a SPA and would like to organize my widgets in the same way that durandal does with "FolderWidgetName" and the folder would contain a controller.js and view.html file. I tried using the getView() method in my controller.js file but could never get it to look in the current folder for the view.
getView(){
return "view"; // looks in the "App" folder
return "./view"; // looks in the "App/durandal" folder
return "/view"; // looks in the root of the website
return "dashboard/widgets/htmlviewer/view" //don't want to hard code the path
}
I don't want to hardcode the path inside of the controller
I don't want to override the viewlocator because the rest of the app still functions as a regular durandal spa that uses standard conventions.
You could use define(['module'], function(module) { ... in order to get a hold on the current module. getView() would than allow you to set a specific view or, like in the example below, dynamically switch between multiple views.
define(['module'], function(module) {
var roles = ['default', 'role1', 'role2'];
var role = ko.observable('default');
var modulePath = module.id.substr(0, module.id.lastIndexOf('/') +1);
var getView = ko.computed(function(){
var roleViewMap = {
'default': modulePath + 'index.html',
role1: modulePath + 'role1.html',
role2: modulePath + 'role2.html'
};
this.role = (role() || 'default');
return roleViewMap[this.role];
});
return {
showCodeUrl: true,
roles: roles,
role: role,
getView: getView,
propertyOne: 'This is a databound property from the root context.',
propertyTwo: 'This property demonstrates that binding contexts flow through composed views.',
moduleJSON: ko.toJSON(module)
};
});
Here's a live example http://dfiddle.github.io/dFiddle-1.2/#/view-composition/getView
You can simply bind your setup view to router.activeRoute.name or .url and that should do what you are looking for. If you are trying to write back to the setup viewmodels property when loading you can do that like below.
If you are using the revealing module you need to define the functions and create a module definition list and return it. Example :
define(['durandal/plugins/router', 'view models/setup'],
function(router, setup) {
var myObservable = ko.observable();
function activate() {
setup.currentViewName = router.activeRoute.name;
return refreshData();
}
var refreshData = function () {
myDataService.getSomeData(myObservable);
};
var viewModel = {
activate: activate,
deactivate: deactivate,
canDeactivate: canDeactivate
};
return viewModel;
});
You can also reveal literals, observables and even functions directly while revealing them -
title: ko.observable(true),
desc: "hey!",
canDeactivate: function() { if (title) ? true : false,
Check out durandal's router page for more info on what is available. Also, heads up Durandal 2.0 is switching up the router.
http://durandaljs.com/documentation/Router/
Add an activate function to your viewmodel as follows:
define([],
function() {
var vm = {
//#region Initialization
activate: activate,
//#endregion
};
return vm;
//#region Internal methods
function activate(context) {
var moduleId = context.routeInfo.moduleId;
var hash = context.routeInfo.hash;
}
//#endregion
});

Knockoutjs - function inside viewmodel causing undesirable recursion

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();