My goal is to create new entity of a new type and push it to manager.
I've created new entity type:
var newType = new breeze.EntityType({
shortName: "input"
});
To be able to create new entity of this type I need to fetch metadata first:
var entityManager = new breeze.EntityManager('api/Db');
entityManager.fetchMetadata(success, failed);
function success(){
var newEntity = entityManager.createEntity('input', {});
}
function failed(){}
The problem is that I have an error on the line entityManager.fetchMetadata(): "TypeError: Cannot call method 'then' of undefined"
Why I'm seeing this error?
does fetchMetadata() tries to http: GET metadata from somewhere? I don't have it anywhere.. How to create the metadata then?
UPDATE:
following suggestions I've rewrite code into:
//create new entity type
var newType = new breeze.EntityType({
shortName: "input",
autoGeneratedKeyType: breeze.AutoGeneratedKeyType.KeyGenerator
});
//add property
var info = new breeze.DataProperty({
name: "text",
dataType: breeze.DataType.String,
isNullable: true,
isPartOfKey: true,
maxLength: 20
});
newType.addProperty(info);
//create metadata on fly
var metadataStore = new breeze.MetadataStore();
metadataStore.addEntityType(newType);
var dataService = new breeze.DataService({
serviceName: 'isdataservice',
hasServerMetadata: false
});
var entityManager = new breeze.EntityManager({
dataService: dataService,
metadataStore: metadataStore
});
//create entry
var entity = entityManager.createEntity('input', { name: "nnn" });
Breeze metadata is information about all the objects you have to work with. You can fetch metadata from server-side or you can create metadata by yourself and work with it.
If you want to work with your server-side objects in breeze you create an entity manager with var entityManager = new breeze.EntityManager('api/Db'); where api/db is your asp.net controller. This controller should have a Metadata() method which returns repository.Metadata(). In js you call entityManager.fetchMetadata().then(success, failed); After the promise of fetchMetadata() is resolved, breeze metadata of variable entityManager is full-filled and you can start working with your server-side objects in js with breeze!
But you can also work without any metadata from server-side and create it on the fly in your js code. You create your own metadataStore, attach it to entitymanager. Pseudo code:
var myMetadataStore = new breeze.MetadataStore();
myMetadataStore.addEntityType({...});
var dataService = new breeze.DataService({
serviceName: 'demo',
hasServerMetadata: false
});
var entityManager = new breeze.EntityManager({
dataService: dataService,
myMetadataStore: store
});
var entity = manager.createEntity(...);
Here is a working sample from breeze with on-the-fly metadata http://www.breezejs.com/breeze-labs/breezedirectivesvalidation
You click on code button or just go to http://plnkr.co/edit/lxPAbIJmRaLmyagXQAFC?p=info to see sources
Also take a look at this link in breeze docs http://www.breezejs.com/documentation/metadata
Related
I have an OData API which is working fine and returns the expected result. When I add ThrottlingHandler() derived from DeletgatingHandler with OData Route it throws
error:
500 Internal Server Error
The response does not contain any data.
OData Route:
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Session>(ControllerResources.Session);
var model = builder.GetEdmModel();
var pathHandler = new DefaultODataPathHandler();
var routingConventions = ODataRoutingConventions.CreateDefault();
var routeConstraint = new ODataPathRouteConstraint(pathHandler, model, Area, routingConventions);
var route = new ODataRoute(ControllerResources.ODataRoutePrefix, routeConstraint, new HttpRouteValueDictionary(), new HttpRouteValueDictionary(), new HttpRouteValueDictionary(), **new ThrottlingHandler()**);
routes.Add(Area, route);
ThrottlingHandler() : DelegateHandler
returnValue = base.SendAsync(request, cancellationToken);
return returnValue;
#Sukhvinder Uppal
I think this is resolved after syncing. Right?
I am binding all the columns of a table except one which is drop down. The table is tied to a model(ODataModel) and the contents of the drop downs in the last columns are all the coming from different model because user shall be selecting one item from the drop down later which is submitted on the click of a button 'Save' I have provided in the bottom.
I am making use of Paginator as Navigation mode. The problem is dropdown shows the contents of first page when user switches between the pages which is eventual as it is not tied to any of the fields in the model of the table. I want to show the respective changes to be reflected in the column of drop down though user switches between the pages.
Any suggestion over this? I know there is something called RowRepeater using which complex controls can be repeated but still what would be the way if I want to make use of sap.ui.table.Table?
Please find my code below:
createAssignResourcesTable: function(){
var model = new sap.ui.model.odata.ODataModel("/sap/opu/odata/sap/ZSECENTRAL_SRV", true);
var substituteRMCombo = sap.ui.getCore().byId("substituteRM");
var selectedRM = substituteRMCombo.getSelectedKey();
var jsonModel = new sap.ui.model.json.JSONModel();
var resourceData = null;
var readSuccess = function(responseData){
resourceData = responseData;
jsonModel.setData(resourceData);
};
var readError = function(){
//console.log('some error occurred while reading data');
sap.ui.commons.MessageBox.show("Some Error occurred while reading data",
sap.ui.commons.MessageBox.Icon.ERROR,"Error!",[sap.ui.commons.MessageBox.Action.OK],
function(){
//console.log('End Date should be grater than Start aDte!!!');
return;
});
};
model.read("/RMResourceSet",null, null, true,readSuccess,readError);
var template = new sap.ui.core.ListItem();
//console.log(template);
template.bindProperty("text","ChildbpName");
template.bindProperty("key","Childbp");
//console.log(template);
var that = this;
var table = new sap.ui.table.Table("assignResourcesTable",{
visibleRowCount: 6,
navigationMode: sap.ui.table.NavigationMode.Paginator,
columns:[
new sap.ui.table.Column("",{
label: new sap.ui.commons.Label({text:"Work Item"}),
template: new sap.ui.commons.Label().bindProperty("text", "DemoId"),
sortProperty: "DemoId",
filterProperty: "DemoId",
width: "auto"
}), new sap.ui.table.Column("",{
label: new sap.ui.commons.Label({text:"Requierd Date"}),
template: new sap.ui.commons.TextView().bindProperty("text", "ReqDate"),
sortProperty: "ReqDate",
filterProperty: "ReqDate",
width: "auto"
}),
new sap.ui.table.Column({
label: new sap.ui.commons.Label("",{
text: "Estimated Hours"
}),
template: new sap.ui.commons.TextField("",{
change:[{"name" : "DurEst"},that.onChangeAssignResourcesTable,that],
value: "00015"
}).bindProperty("value","DurEst")
}),
new sap.ui.table.Column({
label: new sap.ui.commons.Label({text:"Demo Engineer"}),
template: new sap.ui.commons.ComboBox("",{
change:[{"name" : "Childbp"},that.onChangeAssignResourcesTable,that]
}).setModel(jsonModel).bindItems("/results",template),
width: "auto"
})
]
});
table.setBusyIndicatorDelay(1);
var oModel = new sap.ui.model.odata.ODataModel("/sap/opu/odata/sap/ZSECENTRAL_SRV",true);
oModel.attachRequestSent(function (oEvent) {
//console.log('request sent');
table.setBusy(true);
});
oModel.attachRequestCompleted(function () {
//console.log('request completed');
table.setBusy(false);
});
oModel.attachRequestFailed(function () {
table.setBusy(false);
});
table.setModel(oModel);
var FilterOperator = sap.ui.model.FilterOperator;
var filter = new sap.ui.model.Filter("RmUser", FilterOperator.EQ, selectedRM);
table.bindRows("/RMNONSTAFFEDDBRSet",null,null,[filter]);
//table.bindRows("/RMNONSTAFFEDDBRSet",true);
return table;
}
Thanks in Advance!
Your ComboBox statically binds against jsonModel>results. Given the above code I would assume your ComboBox turns out to always contain the very same items.
I understood from your question that these items should be dynamic for each row or at least each page. Since the rows of a table can only be bound to one collection you have the following possibilities to tweak this:
Create a new JSONModel joining the data from your ODataModel with the data used for the ComboBox creation and bind your table against this new model.
Option 1 certainly has some weaknesses so here's another one: Bind your ComboBox column against any property of the ODataModel and use a formatter function to dynamically create the ComboBox items and return them from the formatter.
I'm new on Breezee, I'm looking the examples and Breezee has good support for EntityFramework.
readonly EFContextProvider<TodosContext> _contextProvider =
new EFContextProvider<TodosContext>();
// ~/breeze/todos/Metadata
[HttpGet]
public string Metadata() {
return _contextProvider.Metadata();
}
But actually my data model is LinqToSql. Can I use Breezee with LinqToSql? How do I configure the metadata?
Thanks
You will need to either
1) construct the metadata yourself on the server in json format and return that. See Metadata format.
or
2) create the metadata on the client using the MetadataStore api and then configure your dataservice so that it does not expect server side metadata. The Edmunds example in the Breeze zip shows an example of doing something like this.
var dataService = new DataService({
serviceName: "MyServiceName",
hasServerMetadata: false
});
ver myEntityManager = new EntityManager({
dataService: dataService,
});
We are setting breeze metadata via metadataStore and we were using this approach for months now. But the other day we realized even if we use metadataStore to set metadata, breeze makes a request to server to get metadata-it was not making this request a few versions back (I'm not sure which version, but I can trace back).
I coded a T4 template to generate a slightly modified metadata, but breeze doesn't use this, always loads metadata from server and overrides mine.
Here how we set our metadata;
var core = breeze.core,
entityModel = breeze.entityModel,
serviceName = 'api/Service',
metadataStore = new entityModel.MetadataStore();
metadataStore.importMetadata($.toJSON(metadata));
var createManager = function () {
return new entityModel.EntityManager({
serviceName: serviceName,
metadataStore: metadataStore
});
};
Thanks in advance.
You need to create a DataService with 'hasServerMetadata' set to false:
var dataService = new DataService({
serviceName: serviceName,
hasServerMetadata: false
});
return new EntityManager({
dataService: dataService,
metadataStore: metadataStore
});
Hope this helps.
I have a SPA application (durandaljs), and I have a specific route where I map the "id" of the entity that I want to fetch.
The template is "/#/todoDetail/:id".
For example, "/#/todoDetail/232" or "/#/todoDetail/19".
On the activate function of viewmodel, I get the route info so I can grab the id. Then I create a new instance of breezejs EntityManager to get the entity with the given id.
The problem is when I call manager.fetchEntityByKey("Todos", id), the EntityManager doesn't have yet the metadata from the server, so it throwing exception "Unable to locate an 'Type' by the name: Todos".
It only works if first I execute a query against the store (manager.executeQuery), prior to calling fetchEntityByKey.
Is this an expected behavior or a bug ? Is there any way to auto-fecth the metadata during instantiation of EntityManager ?
note: I believe it's hard to use a shared EntityManager in my case, because I want to allow the user directly type the route on the browser.
EDIT: As a temporary workaround, I'm doing this:
BreezeService.prototype.get = function (id, callback) {
var self = this;
function queryFailed(error) {
app.showMessage(error.message);
callback({});
}
/* first checking if metadatastore was already loaded */
if (self.manager.metadataStore.isEmpty()) {
return self.manager.fetchMetadata()
.then(function (rawMetadata) {
return executeQuery();
}).fail(queryFailed);
} else {
return executeQuery();
}
/* Now I can fetch */
function executeQuery() {
return self.manager.fetchEntityByKey(self.entityType, id, true)
.then(callback)
.fail(queryFailed);
}
};
You've learned about fetchMetadata. That's important. If you application can begin without issuing a query, you have to use fetchMetadata and wait for it to return before you can perform any operations directly on the cache (e.g., checking for an entity by key in the cache before falling back to a database query).
But I sense something else going on because you mentioned multiple managers. By default a new manager doesn't know the metadata from any other manager. But did you know that you can share a single metadataStore among managers? You can.
What I often do (and you'll see it in the metadata tests in the DocCode sample), is get a metadataStore for the application, write an EntityManager factory function that creates new managers with that metadataStore, and then use the factory whenever I'm making new managers ... as you seem to be doing when you spin up a ViewModel to review the TodoDetail.
Coming from a Silverlight background where I used a lot of WCF RIA Services combined with Caliburn Micro, I used this approach for integrating Breeze with Durandal.
I created a sub folder called services in the App folder of the application. In that folder I created a javascript file called datacontext.js. Here is a subset of my datacontext:
define(function (require) {
var breeze = require('lib/breeze'); // path to breeze
var app = require('durandal/app'); // path to durandal
breeze.NamingConvention.camelCase.setAsDefault();
// service name is route to the Web API controller
var serviceName = 'api/TeamData',
// manager is the service gateway and cache holder
manager = new breeze.EntityManager(serviceName),
store = manager.metadataStore;
function queryFailed(error) {
app.showMessage("Query failed: " + error.message);
}
// constructor overrides here
// included one example query here
return datacontext = {
getSponsors: function (queryCompleted) {
var query = breeze.EntityQuery.from("Sponsors");
return manager
.executeQuery(query)
.then(queryCompleted)
.fail(queryFailed)
}
};
}
Then in your durandal view models you can just require the services/datacontext. For example, here is part of a sample view model from my app:
define(function (require) {
var datacontext = require('services/datacontext');
var ctor = function () {
this.displayName = 'Sponsors',
this.sponsors = ko.observable(false)
};
ctor.prototype.activate = function () {
var that = this;
return datacontext.getSponsors(function (data) { that.sponsors(data.results) });
}
return ctor;
});
This will allow you to not worry about initializing the metadata store in every view model since it is all done in one place.