PROBLEM
Durandal or perhaps RequireJS seems to be making my properties null. My main view model has 3 sub models (PostModel, CategoryModel, TagModel) and all of these end up being empty objects.
CODE
Main File: blog.js
var viewModel;
define(['jquery', 'knockout', 'datajs', 'OData', 'Q', 'breeze', 'blog-posts', 'blog-categories', 'blog-tags'],
function ($, ko, datajs, odata, Q, breeze, posts, categories, tags) {
'use strict'
var ViewModel = function () {
var self = this;
self.postModel = false;
self.categoryModel = false;
self.tagModel = false;
self.activate = function () {
self.postModel = new posts();
self.categoryModel = new categories();
self.tagModel = new tags();
};
self.attached = function () {
breeze.config.initializeAdapterInstances({ dataService: "OData" });
self.postModel.init();
self.categoryModel.init();
self.tagModel.init();
};
self.showCategories = function () {
//.....
};
self.showPosts = function () {
//.....
};
self.showTags = function () {
//.....
};
};
viewModel = new ViewModel();
return viewModel;
});
post.js
define(['jquery', 'jqueryval', 'knockout', 'kendo', 'kendo-knockout', 'notify'],
function ($, jqueryval, ko, kendo, ko_kendo, notify) {
'use strict'
var PostModel = function () {
var self = this;
self.id = ko.observable(0);
self.categoryId = ko.observable(0);
self.headline = ko.observable(null);
self.slug = ko.observable(null);
self.teaserImageUrl = ko.observable(null);
self.shortDescription = ko.observable(null);
self.fullDescription = ko.observable(null);
self.useExternalLink = ko.observable(false);
self.externalLink = ko.observable(null);
self.metaKeywords = ko.observable(null);
self.metaDescription = ko.observable(null);
self.availableTags = ko.observableArray([]);
self.chosenTags = ko.observableArray([]);
self.init = function () {
//..... this code runs fine (initializes a Kendo Grid)
};
self.create = function () {
//.....
};
self.edit = function (id) {
//.....
};
self.remove = function (id) {
//.....
};
self.save = function () {
//.....
};
self.cancel = function () {
//.....
};
self.validator = $("#post-form").validate({
rules: {
// JQuery Validation Rules
}
});
};
return PostModel
tag.js
define(['jquery', 'jqueryval', 'knockout', 'kendo', 'kendo-knockout', 'notify'],
function ($, jqueryval, ko, kendo, ko_kendo, notify) {
'use strict'
var TagModel = function () {
var self = this;
self.id = ko.observable(0);
self.name = ko.observable(null);
self.urlSlug = ko.observable(null);
self.init = function () {
//..... this code runs fine (initializes a Kendo Grid)
};
self.create = function () {
//.....
};
self.edit = function (id) {
//.....
};
self.remove = function (id) {
//.....
};
self.save = function () {
//.....
};
self.cancel = function () {
//.....
};
self.validator = $("#tag-form").validate({
rules: {
// JQuery Validation Rules
}
});
};
return TagModel;
});
category.js
define(['jquery', 'jqueryval', 'knockout', 'kendo', 'kendo-knockout', 'notify'],
function ($, jqueryval, ko, kendo, ko_kendo, notify) {
'use strict'
var CategoryModel = function () {
var self = this;
self.id = ko.observable(0);
self.name = ko.observable(null);
self.urlSlug = ko.observable(null);
self.init = function () {
//..... this code runs fine (initializes a Kendo Grid)
};
self.create = function () {
//.....
};
self.edit = function (id) {
//.....
};
self.remove = function (id) {
//.....
};
self.save = function () {
//.....
};
self.cancel = function () {
//.....
};
self.validator = $("#category-form").validate({
rules: {
// JQuery Validation Rules
}
});
};
return CategoryModel;
});
NOTES
init()
functions works fine, since they initialize kendo grids and I can see them working fine.create()
on any of them, they throw errors about the fields being null. Example: self.validator is undefined
(I call reset on the validator inside create()
).alert(JSON.stringify(viewModel.postModel));
This just shows {}
, so we can see an empty object here.WHAT I HAVE TRIED
var CategoryModel = {}
instead of:
var CategoryModel = function () {};
That seemed to prevent the viewModel.postModel
and others from being null, BUT it caused other problems. Mostly scoping problems with the this
keyword and I couldn't set var self = this;
anywhere successfully - even when I did it in activate()
, it would still not work - I would get the main view model or something else when accessing this
. So I think the way I have it setup now is the safest regarding scoping, but for some reason those 3 fields are always NULL.
I have been tearing my hair out for days on this one. Can anyone help me?
EDIT
When I run the following in the console:
alert(JSON.stringify(viewModel))
I get:
{"postModel":{},"categoryModel":{},"tagModel":{},"__moduleId__":"viewmodels/admin/blog"}
As you can see, the 3 child models are empty objects and for some reason, the following functions are missing as well:
self.showCategories = function () { }
self.showPosts = function () { }
self.showTags = function () { }
I have completely run out of ideas on this one...
Alright, for some reason self.validator
was always NULL. My guess is the module is being evaluated before the HTML is injected into the Durandal placeholder. Therefore, when self.validator = $("#post-form").validate({
is being evaluated, the form with ID #post-form
does not exist on the page and therefore self.validator
is undefined.
So my solution was to only assign self.validator
in my init()
function which is called during the attached
callback in the Durandal lifecycle.