Sunday, 18 August 2013

Durandal looses knockout binding

Durandal looses knockout binding

Guru Guys)
I've faced strange(for me) trouble.
In my SPA I have such route structure:
shell - some navigational logic is here.
designs - designs list with filtering, sorting and searching. if user
clicks on list item, he is redirected to it's details page.
designs/details/:id - detailed view of separate design from list.
Shell has main menu and composition binding for specific menus: for
designs list i have strip with filtering, sorting and searching buttons.
For design details i switch it to strip with download button and 'come
back' button, which returns user to design list.
So, the problem is: when i open design list, everything is ok. But, when i
go to details of some item. and after that come back to list, all bindings
in composed view are broken. In console i have ""Unable to parse
bindings.↵Message: ReferenceError: categories is not
defined;↵Bindings value: foreach: categories"".
I suspect, that something is wrong with my promises objects. because i'm
newbee in promises) Can You, please, give me some advices? Here is my
markup and code:
shell.js(shortened)
define(['durandal/plugins/router', 'fw/service'], function (router,
service, userDataModel) {
var o = function () {
var self = this;
/*Current view and viewmodel for composed menu*/
self.currentNavView = ko.observable('views/shellnav');
self.currentNavModel = ko.observable('viewmodels/shell');
/*Router*/
self.router = router;
/*Route activation*/
self.activate = function(args){
/*navigate to designs list*/
router.activate('designs');
}
return self;
}
return new o();});
designs.js
here is the possible problem - when visiting this page first time,
self.categories is filled with data. when coming back to this page from
details - self.categories are empty. categories are the datasource for one
of my filters. they are bound in designsnav.html, and, when coming back
from details, knockout throws an error, that they are not defined.
define(['datamodels/designsdatamodel', 'datamodels/categoryDataModel',
'durandal/app', 'viewmodels/shell', 'durandal/plugins/router',
'viewmodels/designDetails', "fw/service"], function (designModel,
categoryModel, app, shell, router, designsDetails, service) {
var o = function () {
var self = this,
self.designs = ko.observableArray([]),
self.categories = ko.observableArray([]);
self.activate = function (args) {
shell.currentNavView('views/designsnav');
shell.currentNavModel('viewmodels/designs');
var ret = $.when(designModel.getItems(), categoryModel.getItems());
ret.done(function (designsData, categoryData) {
designs(designsData);
categories(categoryData);
});
return ret;
}
/*Displaying design details*/
self.detailClick = function (design) {
router.navigateTo("#/designs/details/" + design.id());
};
return self;
};
return new o();});
designsDataModel.js - here i retrieve data from server and return promices
for list and separate design.
define(['fw/service'], function (service) {
var o = function () {
var self = this;
self.designs = null;
self.getDesign = function (id) {
var dur = $.Deferred();
$.when(service.getDesignDetail(id)).done(function (data) {
dur.resolve(new self.DesignsModel(data))
});
return dur.promise();
};
self.getItems = function () {
var dur = $.Deferred();
$.when(service.getDesigns(opts)).done(function (data) {
var newItems = $.map(data.Items, function (item) { return new
self.DesignsModel(item) });
dur.resolve(newItems);
});
return dur.promise();
};
self.DesignsModel = function (data) {
var self = this;
/*other fields are removed for less displaying*/
};
return self;
}
return new o();
});
categoryDataModel.js - here i receive categories list from server.
define(['fw/service'], function (service) {
var o = function () {
var self = this;
self.getItems = function () {
var dur = $.Deferred();
$.when(service.getCategories()).done(function (data) {
var categories = $.map(data.Items, function (item) { return
new self.CategoryModel(item) });
dur.resolve(categories);
});
return dur.promise();
};
self.CategoryModel = function (data) {
this.id = ko.observable(data.Id);
this.title = ko.observable(data.Title);
this.count = ko.observable(data.Count);
this.selected = ko.observable(false);
}
return self;
}
return new o();});
designDetails.js - when coming back from this to design list, all bindings
from composed view are broken.
define(['viewmodels/shell', 'datamodels/designsdatamodel',
'durandal/plugins/router', 'viewmodels/designs'], function (shell,
designsDM, router, designs) {
var self = this;
self.design = ko.observable();
self.backClick = function () {
shell.currentNavView('views/designsnav');
shell.currentNavModel('viewmodels/designs');
router.navigateTo("#/designs");
};
self.zoomImage = function () {
var $cont = $('.top-container-left');
if ($cont.is(".zoomed")) {
$cont.removeClass("zoomed");
} else {
$cont.addClass("zoomed");
}
};
self.activate = function (args) {
var dur = $.when(designsDM.getDesign(args.id));
shell.currentNavView('views/designDetailsNav');
dur.done(function (data) {
if (data.viewed() === false)
{
data.views(parseInt(data.views()) + 1);
data.viewed(true);
}
self.design(data);
});
return dur;
};
return self;});
I understand, that i've posted a lot of code, but, maybe, somebody will
see rude mistake somewhere - in code or in logic. I will be very grateful
for all constructive coments. Thanks in advance!

No comments:

Post a Comment