I'm trying to configure a few models with breeze.js
The first is session and I was able to get this working perfectly with a simple query like the below
var query = breeze.EntityQuery.from("sessions").toType("Session");
..but when I tried to add a related "speakers" array to the session I seem to be left with an empty array after the materialization step is complete
Do I need to write a custom json adapter for an api that looks like this?
/api/sessions/
[
{
"id": 1,
"name": "javascript",
"speakers": [
1
]
}
]
/api/speakers/1/
{
"id": 1,
"name": "Toran",
"session": 1
}
Here is my current model configuration (mostly working)
var ds = new breeze.DataService({
serviceName: 'api',
hasServerMetadata: false,
useJsonp: false
});
breeze.config.initializeAdapterInstance("modelLibrary", "backingStore", true);
this.instance = new breeze.EntityManager({dataService: ds});
this.instance.metadataStore.addEntityType({
shortName: "Speaker",
namespace: "App",
dataProperties: {
id: { dataType: "Int64", isPartOfKey: true },
name: { dataType: "String" },
session: { dataType: "Int64" }
},
navigationProperties: {
session: {
entityTypeName: "Session", isScalar: true,
associationName: "session", foreignKeyNames: ["session"]
}
}
});
this.instance.metadataStore.addEntityType({
shortName: "Session",
namespace: "App",
dataProperties: {
id: { dataType: "Int64", isPartOfKey: true },
name: { dataType: "String" },
speakers: { dataType: "Undefined" }
},
navigationProperties: {
speakers: {
entityTypeName: "Speaker", isScalar: false,
associationName: "speakers", foreignKeyNames: ["speakers"]
}
}
});
Thanks for the help !
note** I'm using ember.js (not backbone/ko/angular)
I tried to keep the above brief but if you need absolutely everything, checkout this single js file
https://github.com/toranb/embereeze/blob/master/website/static/website/js/app.js
update
if I remove the "speakers" dataProperty breeze gets fairly unhappy in this block of code (as it's not a dataProperty on the session model)
var fkProps = fkNames.map(function (fkName) {
//fkName is speakers .... yet it's not a data property so bad things happen :(
return parentEntityType.getDataProperty(fkName);
});
var fkPropCollection = parentEntityType.foreignKeyProperties;
// Array.prototype.push.apply(parentEntityType.foreignKeyProperties, fkProps);
fkProps.forEach(function (dp) {
I just did a PR - the association name should be the same on both ends, much like any relational database would have.
this.instance.metadataStore.addEntityType({
shortName: "Speaker",
namespace: "App",
dataProperties: {
id: { dataType: "Int64", isPartOfKey: true },
name: { dataType: "String" },
session: { dataType: "Int64" }
},
navigationProperties: {
sessionModel: {
entityTypeName: "Session", isScalar: true,
associationName: "Speaker_Sessions", foreignKeyNames: ["session"]
}
}
});
this.instance.metadataStore.addEntityType({
shortName: "Session",
namespace: "App",
dataProperties: {
id: { dataType: "Int64", isPartOfKey: true },
name: { dataType: "String" }
},
navigationProperties: {
speakers: {
entityTypeName: "Speaker", isScalar: false,
associationName: "Speaker_Sessions"
}
}
});
So I renamed the association, removed the extra speakers property on the Session (there is no property for the relationship, simply an inverse that should be mapped) and then removed the foreign key on the session as you don't need one there. By assigning passing session down from the API with the models shown above should be enough to let Breeze know
Speakers' have a session property, which is a foreign key pointing to a single session.
Sessions have a collection of speakers, which should be mapped on the other end
Related
I try to fill a treelist with remote data via a ajax proxy but the treelist shows only the first level and try to reload the sub levels even though the json response contain a complete tree structure. Fiddle link: https://fiddle.sencha.com/#view/editor&fiddle/33u9
When i try to expand the node 'SUB a' (or set the expanded property to true) the store trys to reload the node.
Why is the tree structure from the json response not honored?
Thanks in Advance.
The backend response looks like:
{
"data": {
"root": [
{
"leaf": true,
"text": "Server"
},
{
"leaf": true,
"text": "Storage"
},
{
"text": "SUB a"
"children": [
{
"leaf": true,
"text": "Modul A - 1"
},
{
"leaf": true,
"text": "Modul A - 2"
}
],
},
{
"leaf": true,
"text": "Modul B"
}
]
},
"success": true
}
The used reader config is
reader: {
type: 'json',
rootProperty: 'data.root',
successProperty: 'data.success',
},
After playing around i use the following workaround:
getNavigation: function() {
var me = this,
tree = me.getView().down('navigationtree'),
store = tree.getStore(),
node = store.getRoot();
Ext.Ajax.request({
url: '/getnav',
method: 'POST',
success: function(response) {
var obj = Ext.decode(response.responseText),
childs = obj.data.root;
tree.suspendEvents();
node.removeAll();
childs.forEach(function(item) {
node.appendChild(item);
});
tree.resumeEvents();
},
failure: function(response) {
//debugger;
console.log('server-side failure with status code ' + response.status);
}
}).then(function() {
//debugger;
}
);
}
The funny things is that only the first level of the tree has to be added all following sub-levels are added automaticaly.
I am sorting Kendo grid dynamically.
var sortedName = $('##Html.FieldIdFor(model => model.SortingName)').val();
var sortedOrderName = $('##Html.FieldIdFor(model => model.SortingOrderName)').val();
sort: { field: sortedName, dir: sortedOrderName },
it is working fine but this is sorting records by pagination. What I want is to sort all the data fetched from the database
I recommend looking at the remote data binding example: Kendo Grid Remote-Data-Binding
Note the Data Source settings for serverPaging, serverFiltering and server sorting:
dataSource: {
type: "odata",
transport: {
read: "//demos.telerik.com/kendo-ui/service/Northwind.svc/Orders"
},
schema: {
model: {
fields: {
OrderID: { type: "number" },
Freight: { type: "number" },
ShipName: { type: "string" },
OrderDate: { type: "date" },
ShipCity: { type: "string" }
}
}
},
pageSize: 20,
serverPaging: true,
serverFiltering: true,
serverSorting: true
}
When calling addEntityType for ResourceUnavailabilities, I get the error: error configuring an instance of 'NavigationProperty'. The 'entityTypeName' parameter must be a 'string'
I don't get it. I've looked at the tutorial on breeze's website, and I can't tell what I'm doing wrong.
client-side model:
metadataStore.addEntityType({
shortName: 'Unavailability',
namespace: 'ecdt',
dataProperties: {
id: { dataType: DT.Guid, isPartOfKey: true },
startDate: { dataType: DT.DateTimeOffset },
endDate: { dataType: DT.DateTimeOffset },
isDayOff: { dataType: DT.Boolean }
}
});
metadataStore.registerEntityTypeCtor('Unavailability', null, null);
metadataStore.addEntityType({
shortName: 'ResourceUnavailabilities',
namespace: 'ecdt',
dataProperties: {
id: { dataType: DT.Guid, isPartOfKey: true },
resourceId: { dataType: DT.Int32 },
},
navigationProperties: {
unavailabilities: { dataType: 'Unavailability', hasMany: true }
}
});
metadataStore.registerEntityTypeCtor('ResourceUnavailabilities', null, null);
Apart from that everthing works fine. I can create Unavailability entities and also ResourceUnavailabilities entities (as long as I remove the navigation property...)
Also, in the tutorial, you use the nameproperty instead of shortname. If I do that, I get an error
Error configuring an instance of 'EntityType'. Unknown property: 'name'. Is the sample out-of-date ?
Ok, it's solved. The correct mapping is:
metadataStore.addEntityType({
shortName: 'Unavailability',
namespace: 'ecdt',
dataProperties: {
id: { dataType: DT.Guid, isPartOfKey: true },
startDate: { dataType: DT.DateTimeOffset },
endDate: { dataType: DT.DateTimeOffset },
isDayOff: { dataType: DT.Boolean }
},
navigationProperties: {
unavailabilities: { entityTypeName: 'ResourceUnavailabilities', isScalar: true, associationName: "test" }
}
});
metadataStore.registerEntityTypeCtor('Unavailability', null, null);
metadataStore.addEntityType({
shortName: 'ResourceUnavailabilities',
namespace: 'ecdt',
dataProperties: {
id: { dataType: DT.Guid, isPartOfKey: true },
resourceId: { dataType: DT.Int32 },
},
navigationProperties: {
unavailabilities: { entityTypeName: 'Unavailability', isScalar: false, associationName: "test" }
}
});
Looks like the breeze document is not exactly up-to-date.
I am trying to figure out how to write a query that will filter my related entities using the executeQueryLocally.
Here is my example:
var queryStageConfigs = breeze.EntityQuery
.from("Stages")
.where("StageConfig.ConfigValue", '==', 'Green')
.expand("StageConfig");
var stageConfigs = self.manager.executeQueryLocally(queryStageConfigs);
This the error I am getting back:
Error: unable to locate property: ConfigValue on entityType: Stages:#
MetadataStore
//Stages Entity
metadataStore.addEntityType({
shortName: "Stages",
//namespace: "MonitoringCenter",
dataProperties: {
id: { dataType: DT.Int64, isPartOfKey: true },
institutionId: { dataType: DT.Int64 },
qualifiedName: { dataType: DT.String },
displayName: { dataType: DT.String },
displayOrder: { dataType: DT.Int64 },
},
navigationProperties: {
institution: {
entityTypeName: "Stages",
isScalar: true,
associationName: "Institution_Stages",
foreignKeyNames: ["institutionId"]
},
stageConfig: {
entityTypeName: "StageConfig",
isScalar: false,
associationName: "Stages_StageConfig"
}
}
});
metadataStore.setEntityTypeForResourceName("Stages", "Stages");
//StageConfig Entity
metadataStore.addEntityType({
shortName: "StageConfig",
//namespace: "MonitoringCenter",
dataProperties: {
id: { dataType: DT.Int64, isPartOfKey: true },
stageId: { dataType: DT.Int64 },
configName: { dataType: DT.String },
configValue: { dataType: DT.String },
},
navigationProperties: {
stages: {
entityTypeName: "StageConfig",
isScalar: true,
associationName: "Stages_StageConfig",
foreignKeyNames: ["stageId"]
}
}
});
metadataStore.setEntityTypeForResourceName("StageConfig", "StageConfig");
I am hand writing the JsonResultsAdpater to get the JSON data into the entities that have created using the metadataStore setting up the relationship between the entities.
When I query the Stages entities I can see the StageConfigs array and it is not empty.
Any clue on what I may be doing wrong?
Any help would be greatly appreciated!
Ok, your example is a little confusing because I can't tell the cardinality of the relationships based on your names. In general, I think of a pluralized name like 'stages' as being a collection of 'Stage' entities (i.e. isScalar = false). But in your case the 'stages' property is actually scalar and its inverse, the 'stageConfig' property, a singularized name, is actually non-scalar. If this assumption is correct then the reason that your query will not work is because the stage.stageConfig property needs to be a scalar in order for your query to work, unless you want to use the 'any/all' operators. i.e. something like
var queryStageConfigs = breeze.EntityQuery
.from("Stages")
.where("StageConfig", "any", "ConfigValue", "==", 'Green');
.expand("StageConfig");
( and shouldn't the query be called 'queryStages' because you are querying and returning 'stages')
Also, just a nit, but its probably a good idea to keep all of your entityType names singular and your resource names plural. This is not a requirement, but it is certainly confusing the way you have one entityType singularized ( StageConfig) and another pluralized (Stages).
I don't see any mention in your code about using the camelCase naming convention, but the example seems to indicate that you are assuming that this is set.
I'm trying to write a select box in Ember, based on a Rails back end. When editing the model Recipes, I want to be able to select from a list of Sources in a dropdown. Right now in Ember I'm getting the message "The value that #each loops over must be an Array. You passed App.Sources" as a result of the following code.
I have tested the REST api and it is providing the response for Recipes and Sources both properly.
I'm new to Embers (and Javascript too, actually!) and I feel like I'm missing something basic. Thank you for any tips.
Here's my JS:
App.RecipeEditController = Ember.ObjectController.extend({
needs: ['sources'],
selectedSource: null,
actions: {
save: function() {
var recipe = this.get('model');
// this will tell Ember-Data to save/persist the new record
recipe.save();
// then transition to the current recipe
this.transitionToRoute('recipe', recipe);
}
}
});
App.RecipesRoute = Ember.Route.extend({
model: function() {
return this.store.find('recipe');
},
setupController: function(controller, model) {
this._super(controller, model);
this.controllerFor('sources').set('content', this.store.find('source'));
}
});
App.SourcesRoute = Ember.Route.extend({
model: function() {
return this.store.find('source');
}
});
DS.RESTAdapter.reopen({
namespace: "api/v1"
});
App.Recipe = DS.Model.extend({
title: DS.attr('string'),
url: DS.attr('string'),
rating: DS.attr('number'),
source: DS.belongsTo('source', {
async: true
}),
page_number: DS.attr('number'),
want_to_make: DS.attr('boolean'),
favorite: DS.attr('boolean')
});
App.Source = DS.Model.extend({
title: DS.attr('string'),
authorLast: DS.attr('string'),
recipes: DS.hasMany('recipe', {
async: true
})
});
App.Router.map(function() {
return this.resource("recipes");
});
App.Router.map(function() {
return this.resource("recipe", {
path: "recipes/:recipe_id"
});
});
App.Router.map(function() {
return this.resource("recipeEdit", {
path: "recipes/:recipe_id/edit"
});
});
App.Store = DS.Store.extend({
revision: 11,
adapter: DS.RESTAdapter
});
And here's the view:
{{view Ember.Select
contentBinding="controllers.sources.content"
optionLabelPath="content.title"
optionValuePath="content.id"}}
UPDATE And here's the JSON:
{
"recipes": [
{
"id": 3,
"title": "Did this make it through?",
"url": "www.hellyeahitdid.com/high-five/",
"rating": null,
"source_id": null,
"page_number": null,
"want_to_make": false,
"favorite": false
},
{
"id": 1,
"title": "Here's another totally crazy one for ya",
"url": "http://www.example.com/recipe/1",
"rating": null,
"source_id": null,
"page_number": null,
"want_to_make": false,
"favorite": false
},
{
"id": 2,
"title": "A Sample Recipe",
"url": "http://www.example.com/recipe/1",
"rating": null,
"source_id": null,
"page_number": null,
"want_to_make": false,
"favorite": false
}
]
}
{
"sources": [
{
"id": 1,
"title": "Joy of Cooking",
"author_last": null
},
{
"id": 2,
"title": "Everyday Food",
"author_last": null
}
]
}
Welcome to javacript/ember, here's an example using a select.
http://emberjs.jsbin.com/OxIDiVU/69/edit
you'll notice the i don't quote real properties, and do quote strings
{{ view Ember.Select
content=someSource
optionValuePath='content.id'
optionLabelPath='content.title'
}}
Additionally that appears to be a very old version of Ember Data. You may consider updating. https://github.com/emberjs/data/blob/master/TRANSITION.md
Your routing can go in a single call
App.Router.map(function() {
this.resource("recipes");
this.resource("recipe", { path: "recipes/:recipe_id"}, function(){
this.route('edit');
});
});
This should get you started
http://emberjs.jsbin.com/OxIDiVU/74/edit