问题
I'm getting the following error from breeze and q.js when my view and model are being bound by a compose binding statement using durandal. I wrote the view in question in isolation and it works great until I try to do a compose binding with it, it throws this error. I tried moving all the custom properties from my entity constructor function to the initializer and also defering evalution of my computed's but that did nothing to thwart the error. I'm not sure which framework is causing this problem or if my own code is. I was using a deferred Q promise in my datacontext but I commented it to rule it out and went back to using a standard callback function.
Error:
[Q] Unhandled rejection reasons (should be empty): [TypeError]
Object [object Object] has no method 'isExpanded'
TypeError: Object [object Object] has no method 'isExpanded'? at domainModel.<anonymous> (http://myApp/App/viewmodels/categoryTreeView.js?v=1.0.0.0:31:59)? at evaluateImmediate (http://myApp/Scripts/knockout-2.2.1.debug.js:1241:41)? at Object.ko.dependentObservable (http://myApp/Scripts/knockout-2.2.1.debug.js:1318:9)? at dmInitializer (http://myApp/App/viewmodels/categoryTreeView.js?v=1.0.0.0:30:29)? at proto._postInitialize (http://myApp/scripts/breeze.debug.js:2975:13)? at mergeEntity (http://myApp/scripts/breeze.debug.js:12768:39)? at processMeta (http://myApp/scripts/breeze.debug.js:12685:24)? at visitAndMerge (http://myApp/scripts/breeze.debug.js:12665:16)? at http://myApp/scripts/breeze.debug.js:12972:20? at Array.map (native)?From previous event:? at executeQueryCore (http://myApp/scripts/breeze.debug.js:12593:77)? at proto.executeQuery (http://myApp/scripts/breeze.debug.js:11461:23)? at Object.getCategories (http://myApp/App/services/datacontext.js?v=1.0.0.0:51:17)? at viewModel.self.getCategories (http://myApp/App/viewmodels/categoryTreeView.js?v=1.0.0.0:204:17)? at init (http://myApp/App/viewmodels/categoryTreeView.js?v=1.0.0.0:223:18)? at new viewModel (http://myApp/App/viewmodels/categoryTreeView.js?v=1.0.0.0:225:9)? at Object.<anonymous> (http://myApp/App/durandal/composition.js?v=1.0.0.0:317:42)
categorytreeview.js:
define(["services/datacontext"], function (ctx) {
function domainModel() {
var self = this;
self.isSelected = ko.observable(false);
self.isExpanded = ko.observable(false);
self.toggleIsExpanded = function () {
self.isExpanded(!self.isExpanded());
};
self.toggleIsSelected = function () {
self.isSelected(!self.isSelected());
};
}
var dmInitializer = function (item) {
item.isBranch = ko.computed(function () {
return item.Children().length > 0 || item.ParentCategory() == null;
});
item.isRoot = ko.computed(function () {
return item.ParentCategory() == null;
});
item.isVisible = ko.computed(function() {
return item.isRoot() || item.ParentCategory().isExpanded();
}, item);
};
ctx.metadataStore.registerEntityTypeCtor("Category", domainModel, dmInitializer);
function viewModel() {
var self = this;
self.categories = ko.observableArray();
self.getCategoriesCallback = function (data) {
console.log("callback for getCategories");
self.categories(data.results);
};
self.getCategories = function () {
ctx.getCategories(self.getCategoriesCallback);
};
init = function () {
self.getCategories();
};
init();
}
return viewModel;
}
categorytreeview.html
<div id="categoryTreeView">
<script id="recursiveTemplate" type="text/html">
<ul data-bind="visible: isVisible">
<li data-bind="css: { branch: isBranch, leaf: !isBranch(), expanded: isExpanded }">
<div data-bind="click: toggleIsExpanded"></div>
<div>
<input type="checkbox" data-bind="attr: { id: 'c-' + CategoryId() }, value: CategoryId" />
<label data-bind="text: Name, attr: { for: 'c-' + CategoryId() }"></label>
</div>
</li>
<!-- ko template: { name: 'recursiveTemplate', foreach: Children } --><!-- /ko -->
</ul>
</script>
<div class="css-treeview">
<!-- ko template: { name: 'recursiveTemplate', foreach: categories } --><!-- /ko -->
<div id="dialog-buttons">
<input type="button"
value="Cancel" class="btn-cancel">
<input type="button" value="Save" class="btn-primary pull-right">
</div>
</div>
</div>
This is the html from the main view were I'm composing the failing view:
<div data-bind="compose: { model: categoryMapModel, activate: true, cacheViews: false }">
</div>
datacontext.js
function getCategories(afterGetCategories) {
//var deferred = Q.defer();
var query = breeze.EntityQuery.from("Category")
.orderBy("ParentCategoryId, Name")
.expand("Children");
manager.executeQuery(query)
.then(function (data) {
console.log("callback for getCategories");
//deferred.resolve(data);
afterGetCategories(data);
})
.fail(function (error) { console.log("Error: " + error); });
//return deferred.promise;
};
Update 1:
I’ve ruled Q.js out as a problem, it’s just the last guy in stack. If I assign my categoryMapModel()
with an initial value like below everything works fine. If I then click a UI button that removes and re-shows this view, again everything works fine. If I also wait and set this variable in the activate()
method that durandal calls again everything works just fine.
self.categoryMapModel = ko.observable("viewmodels/categoryTreeView");
However this variable is set during run-time when the user clicks a button and that’s when I get the error. What I’m seeing is that breeze.js is not appending the custom properties from my initialization function to specific entities. As you can see from the logging below when it hits the category entity named “DVD” it bombs out. This entity, for unknown reasons, does not contain any of the custom properties like isExpanded()
or isRoot()
that is defined in the initialization function. Out of all the entities this is the only one that doesn't have the custom properties. There are other entities that come after it in the list and they are fine. I don’t see any logic why breeze would have an issue with a specific entity in this scenario but it is.
What in the world am I doing wrong/What would cause breeze.js to ignore the initialization function?
name: Apparel categoryTreeView.js:269
properties: isSelected, isExpanded, toggleIsExpanded, toggleIsSelected, entityAspect, CreatedOn, CategoryId, PictureId, Name, Description, IsPublished, IsDeleted, ParentCategoryId, Children, Picture, ParentCategory, AdvertiserCategories, isBranch, isRoot, isVisible, path, _$typeName, entityType, _$interceptor, getProperty, setProperty, categoryTreeView.js:270
name: Art categoryTreeView.js:269
properties: isSelected, isExpanded, toggleIsExpanded, toggleIsSelected, entityAspect, CreatedOn, CategoryId, PictureId, Name, Description, IsPublished, IsDeleted, ParentCategoryId, Children, Picture, ParentCategory, AdvertiserCategories, isBranch, isRoot, isVisible, path, _$typeName, entityType, _$interceptor, getProperty, setProperty, categoryTreeView.js:270
name: Books categoryTreeView.js:269
properties: isSelected, isExpanded, toggleIsExpanded, toggleIsSelected, entityAspect, CreatedOn, CategoryId, PictureId, Name, Description, IsPublished, IsDeleted, ParentCategoryId, Children, Picture, ParentCategory, AdvertiserCategories, isBranch, isRoot, isVisible, path, _$typeName, entityType, _$interceptor, getProperty, setProperty, categoryTreeView.js:270
name: Electronics categoryTreeView.js:269
properties: isSelected, isExpanded, toggleIsExpanded, toggleIsSelected, entityAspect, CreatedOn, CategoryId, PictureId, Name, Description, IsPublished, IsDeleted, ParentCategoryId, Children, Picture, ParentCategory, AdvertiserCategories, isBranch, isRoot, isVisible, path, _$typeName, entityType, _$interceptor, getProperty, setProperty, categoryTreeView.js:270
name: Movies categoryTreeView.js:269
properties: isSelected, isExpanded, toggleIsExpanded, toggleIsSelected, entityAspect, CreatedOn, CategoryId, PictureId, Name, Description, IsPublished, IsDeleted, ParentCategoryId, Children, Picture, ParentCategory, AdvertiserCategories, isBranch, isRoot, isVisible, path, _$typeName, entityType, _$interceptor, getProperty, setProperty, categoryTreeView.js:270
name: root node categoryTreeView.js:269
properties: isSelected, isExpanded, toggleIsExpanded, toggleIsSelected, entityAspect, CreatedOn, CategoryId, PictureId, Name, Description, IsPublished, IsDeleted, ParentCategoryId, Children, Picture, ParentCategory, AdvertiserCategories, isBranch, isRoot, isVisible, path, _$typeName, entityType, _$interceptor, getProperty, setProperty, categoryTreeView.js:270
name: Blu-ray categoryTreeView.js:269
properties: isSelected, isExpanded, toggleIsExpanded, toggleIsSelected, entityAspect, CreatedOn, CategoryId, PictureId, Name, Description, IsPublished, IsDeleted, ParentCategoryId, Children, Picture, ParentCategory, AdvertiserCategories, isBranch, isRoot, isVisible, path, _$typeName, entityType, _$interceptor, getProperty, setProperty, categoryTreeView.js:270
*name: DVD categoryTreeView.js:269
*properties: entityAspect, IsDeleted, CategoryId, PictureId, Name, Description, IsPublished, ParentCategoryId, CreatedOn, ParentCategory, Picture, Children, AdvertiserCategories, _$typeName, entityType, _$interceptor, getProperty, setProperty, categoryTreeView.js:270
name: reddisc categoryTreeView.js:269
properties: isSelected, isExpanded, toggleIsExpanded, toggleIsSelected, entityAspect, CreatedOn, CategoryId, PictureId, Name, Description, IsPublished, IsDeleted, ParentCategoryId, Children, Picture, ParentCategory, AdvertiserCategories, isBranch, isRoot, isVisible, path, _$typeName, entityType, _$interceptor, getProperty, setProperty, categoryTreeView.js:270
name: Animation categoryTreeView.js:269
properties: isSelected, isExpanded, toggleIsExpanded, toggleIsSelected, entityAspect, CreatedOn, CategoryId, PictureId, Name, Description, IsPublished, IsDeleted, ParentCategoryId, Children, Picture, ParentCategory, AdvertiserCategories, isBranch, isRoot, isVisible, path, _$typeName, entityType, _$interceptor, getProperty, setProperty, categoryTreeView.js:270
name: Accessories categoryTreeView.js:269
properties: isSelected, isExpanded, toggleIsExpanded, toggleIsSelected, entityAspect, CreatedOn, CategoryId, PictureId, Name, Description, IsPublished, IsDeleted, ParentCategoryId, Children, Picture, ParentCategory, AdvertiserCategories, isBranch, isRoot, isVisible, path, _$typeName, entityType, _$interceptor, getProperty, setProperty, categoryTreeView.js:270
name: test categoryTreeView.js:269
properties: isSelected, isExpanded, toggleIsExpanded, toggleIsSelected, entityAspect, CreatedOn, CategoryId, PictureId, Name, Description, IsPublished, IsDeleted, ParentCategoryId, Children, Picture, ParentCategory, AdvertiserCategories, isBranch, isRoot, isVisible, path, _$typeName, entityType, _$interceptor, getProperty, setProperty, categoryTreeView.js:270
name: test2 categoryTreeView.js:269
properties: isSelected, isExpanded, toggleIsExpanded, toggleIsSelected, entityAspect, CreatedOn, CategoryId, PictureId, Name, Description, IsPublished, IsDeleted, ParentCategoryId, Children, Picture, ParentCategory, AdvertiserCategories, isBranch, isRoot, isVisible, path, _$typeName, entityType, _$interceptor, getProperty, setProperty, categoryTreeView.js:270
name: test23 categoryTreeView.js:269
properties: isSelected, isExpanded, toggleIsExpanded, toggleIsSelected, entityAspect, CreatedOn, CategoryId, PictureId, Name, Description, IsPublished, IsDeleted, ParentCategoryId, Children, Picture, ParentCategory, AdvertiserCategories, isBranch, isRoot, isVisible, path, _$typeName, entityType, _$interceptor, getProperty, setProperty, categoryTreeView.js:270
name: test categoryTreeView.js:269
properties: isSelected, isExpanded, toggleIsExpanded, toggleIsSelected, entityAspect, CreatedOn, CategoryId, PictureId, Name, Description, IsPublished, IsDeleted, ParentCategoryId, Children, Picture, ParentCategory, AdvertiserCategories, isBranch, isRoot, isVisible, path, _$typeName, entityType, _$interceptor, getProperty, setProperty, categoryTreeView.js:270
rootCategories needed
[Q] Unhandled rejection reasons (should be empty): [TypeError]
回答1:
I finally see what's going on! In the main view I have a breeze query that expanded down to the Category
table and I was then loading another view (categoryTreeView) that also needed to query the Category
table. Since the main view loaded first and there was no call to registerEntityTypeCtor
in that view for the Category
entity breeze is essentially caching any entities from that first query as-is. When my second view comes along, and even though I do call registerEntityTypeCtor
in there, it doesn't fire for the entities that were already loaded from the main view's query.
来源:https://stackoverflow.com/questions/17074993/why-am-i-getting-a-typeerror-when-querying-through-breeze-during-a-compose-in-du