I am using ServiceStack to get JSON data to the client. I have setup for BreezeJS to map the ServiceStack calls.
Data return by web service is in format like this:
Meta: {Path:[{"Name":"Root","Id":"00000000000000000000000000000000"}], Duration:145}
Duration: "145"
Path: "[{"Name":"Root","Id":"00000000000000000000000000000000"}]"
Offset: 0
Results: [,…]
0: {Description:SLO, InternalKey:SLO, IsActive:true, Name:SLO, ParentId:00000000000000000000000000000000,…}
ChildCount: 2
CreatedById: "ed85f2b9c0bf46729cbb17cee25e3287"
CreatedDate: "2014-09-06T06:23:16.6000000"
Description: "SLO"
HasChildren: true
Id: "9b636028e3f04535a5147a2df375adaa"
InstanceType: "Container"
InternalKey: "SLO"
IsActive: true
ModifiedDate: "2014-09-17T11:04:23.1553432"
Name: "SLO"
ParentId: "00000000000000000000000000000000"
Total: 1
If I create entity manually for node "Result" the data gets mapped and I can read it in my view.
Entity definition:
define(function (require) {
var breeze = require('breeze');
var ctor = function () {
var self = this;
self.DT = breeze.DataType;
};
ctor.prototype.instanceCreate = function (nameSpace) {
var self = this;
return self.instance = {
shortName: "instances",
namespace: nameSpace,
autoGeneratedKeyType: breeze.AutoGeneratedKeyType.Identity,
defaultResourceName: "instances",
dataProperties: {
ConnectionString: { dataType: self.String },
Description: { dataType: self.String },
InternalKey: { dataType: self.String },
IsActive: { dataType: self.Boolean },
Name: { dataType: self.String },
ParentId: { dataType: self.Int32 },
InstanceType: { dataType: self.String },
ChildCount: { dataType: self.Int32 },
HasChildren: { dataType: self.Boolean },
Uid: { dataType: self.Guid },
ETag: { dataType: self.String },
Id: { dataType: self.Int32, isPartOfKey: true },
CreatedDate: { dataType: self.DateTime },
CreatedById: { dataType: self.String },
ModifiedDate: { dataType: self.DateTime },
ModifiedById: { dataType: self.String },
DeletedDate: { dataType: self.DateTime },
DeletedById: { dataType: self.Int32 },
}
};
};
return new ctor();
});
The question is: is it possible in Breeze to define entity so I can read both the "Result" node and the "Meta" from JSON into single entity definition. So I can access data something like:
data.results and data.Meta? Or is there any other way to solve this problem.
I am not sure I fully understand your question. I THINK you're asking if there is a way to map the JSON into an entity by flattening out some of the data and cherry-picking from different nodes.
If so, the answer is ... absolutely. You'll want to create a custom JsonResultsAdapter and probably a custom DataServiceAdapter (which has its own JsonResultsAdapter for handling server responses to a save such as a new instance).
You'll find examples of both adapters in breeze.js itself and in various of the Breeze Labs.
I wish I could point you to documentation and a guide to writing these adapters. It's on our backlog.
FWIW, I would NOT locate persistence metadata such as etag among the entity properties. That's metadata that you need under the covers to make persistence work; it's not "business data" and not something the application developer should see or care about. Which is why in our OData and SharePoint DataService Adapters, we move that kind of thing to the node's result.extraMetadata property. Breeze picks that up and moves it to the entityAspect which is the place to keep persistence info (e.g., change state). Breeze recognizes entityAspect.extraMetadata as a property bag to which you can add anything that you can JSON.stringify.
Related
Try to change the columns list dynamically via a query ...
When I construct the TreeList, I call for columns :
$("#treelist").kendoTreeList({
columns: AnalyseCenterSKUService.getKPIColumnList($scope)
If I return a simple array with the fields, it's working ..
If I call a $http.get (inside my getKPIColumnList(..) function) which add some columns to the existing array of columns, the TreeList is not constructed correctly.
Any suggestion will be really appreciated ! :)
EDIT 22-10-2019 09:00
Treelist init
$("#treelist").kendoTreeList({
columns: AnalyseCenterSKUService.getKPIColumnList($scope),
scrollable: true,
columnMenu : {
columns : true
},
height: "100%",
dataBound: function (e) {
ExpandAll();
},
dataSource: {
schema: {
model: {
id: "id",
parentId: "parentId",
fields: {
id: { type: "number" },
parentId: { type: "number", nullable: true },
fields: {
id: { type: "number" },
parentId: { type: "number", nullable: false }
}
}
}
},
transport: {
read: {
url: "/api/AnalyseCenter/GetWorkOrderTree/0",
dataType: "json"
}
}
}
The getKPIColumnList return an static array + some push with dynamic columns (from DB)
angular.module('AnalyseCenterDirectives')
.service ('AnalyseCenterSKUService', function ($http) {
var toReturn = [ {field: "Name", title: "Hiérachie SKU", width: "30%" }, ..., ..., .... ];
I try in this function to push DB result
return $http.get("/api/AnalyseCenter/GetWorkOrderHistorianAdditonalColumns?equipmentName=" + equipmentName)
.then(function (result) {
var data = result.data;
if (data && data !== 'undefined') {
var fromDB = data;
angular.forEach(fromDB, function (tag) {
var tagName = tag.replace(".","_");
toReturn.push({
field: tagName, title: tag, width: '10%',
attributes: { style: "text-align:right;"} })
})
The stored procedure GetWorkOrderHistorianAdditonalColumns returns a list of string (future column)
That is because ajax is async, that means your tree list is being initialized before the request finishes. A classic question for JavaScript newcomers. I suggest you take a while to read about ajax, like How does AJAX works for instance.
Back to your problem. You need to create your tree list inside the success callback(I can't give you a more complete solution since I don't know what you're doing inside your function or which framework you're using to open that ajax request) with the result data, which is probably your columns. Then it would work as if you're initializing it with arrays.
Is it possible in fullcalendar-scheduler to pass start and end date of the view to the resources? eventSources are provided with these two parameters automatically, but resources not. I tried with
resources: {
url: '<?= $resourcesRoute ?>,
type: 'POST',
data: {
start: $('#calendarDaysoff').fullCalendar('getView').start,
}
},
eventSources: [
{
url: '<?= $eventsRoute ?>',
type: 'POST',
data: {
bla: 'bla'
},
error: function () {
alert('There was an error while fetching events!');
}
}
],
but this does not works.
I used this solution:
resources: function(callback){
setTimeout(function(){
var view = $('#calendar').fullCalendar('getView');
$.ajax({
url: 'feed.php',
dataType: 'json',
cache: false,
data: {
start: view.start.format(),
end: view.end.format(),
timezone: view.options.timezone
}
}).then(function(resources){callback(resources)});
},0);
},
This will add start and end parameters like when fetching events. You can add
$feed_start = $_GET['start']; to feed.php
and use the variable '$feed_start' in mysql select.
I got the input from https://github.com/fullcalendar/fullcalendar-scheduler/issues/246?_pjax=%23js-repo-pjax-container
V1.5.1 introduces a solution:
https://fullcalendar.io/docs/resource_data/refetchResourcesOnNavigate/
Since v1.5.1, if refetchResourcesOnNavigate is set to true a resources function will receive start, end, and timezone parameters
I'm using a Kendo Grid with a datasource using type Odata.
I have troubles creating a new row in the database from the datasource.
This is my datasource code:
var ds = new kendo.data.DataSource({
type: "odata",
transport: {
read: {
url: baseUrl,
dataType: "json"
},
update: {
url: function (data) {
return baseUrl + "('" + data.ID_Agenzia + "')";
}
},
create: {
url: baseUrl
},
destroy: {
url: function (data) {
return baseUrl + "('" + data.ID_Agenzia + "')";
}
}
},
schema: {
model: {
id: "ID_Agenzia",
fields: {
ID_Agenzia: { type: "string" },
// etc... my other fields omitted for brevity.
}
}
},
pageSize: 20,
serverPaging: true,
serverFiltering: true,
serverSorting: true
});
Then I tried a simple grid with the automatic toolbar Create (pretty standard, I think I can omit the code), using this DS.
As far as I understood, Kendo got a method "isNew" to discern between Create/Update and it checks if the ID is === to the default value.
All the examples I found googling around, were using the ID as a numeric incremental value... But in my table the ID is a String (obviously unique) that needs to be inserted by the user!!
Hoping I've explained myself well, the issue should be clear: If the user inserts the ID, the datasource won't recognize that it's a Create operation...
Otherwise if I forbit the manual ID insert, the create will work... but the row will be inserted in the DB with the default value (empty string) and this is wrong!
How can I solve this?
Thanks.
[EDIT] Addictional info:
I'm using latest version of Kendo-ui and Odata 2.0
I'm new to breezejs. I am trying to define my entity type in the client without getting metadata from the server. I have a property called ID in the server entity.
I've defaulted the naming convention in the client side to camel case using the following code.
breeze.NamingConvention.camelCase.setAsDefault();
so, I started to map the entity as follows
store.addEntityType({
shortName: "Photo",
namespace: "MyProj.Models",
dataProperties: {
id: {
dataType: DataType.Guid,
isNullable: false,
isPartOfKey: true
},
title: {
dataType: DataType.String
},
description: {
dataType: DataType.String
},
createdDate: {
dataType: DataType.DateTime
},
}
});
This worked all fine, except the id field is not getting the proper value. instead, it has the default value set by the breeze datatype ctor which is equals to Guid.Empty.
by stepping through breezejs debug script, I found out that it looks for a property name called Id in the data that comes from the ajax request. But it can't find it as the property is ID so it initialize it to empty guid string. I assumed that by setting nameOnServer property of the dataProperty id, I will be able to fix it.
store.addEntityType({
shortName: "Photo",
namespace: "MyProj.Models",
dataProperties: {
id: {
dataType: DataType.Guid,
isNullable: false,
nameOnServer: 'ID',
isPartOfKey: true
},
title: {
dataType: DataType.String
},
description: {
dataType: DataType.String
},
createdDate: {
dataType: DataType.DateTime
},
}
});
But it didn't work.
Further digging through the breez.debug.js code, in the method updateClientServerNames on line 7154, it seems it ignores the nameOnServer that I have defined.
Am I missing something here?
Okay, Feel like I spent my whole life through breeze documentation. Anyways, Finally solved the issue. To be honest, this wasn't a problem in breeze (but I wonder why it doesn't override the actual nameOnServer when I provide one). It's an error made by one of the developers in the early stage of the database implementation (probably 6 years ago). If the database adhered to Pascal Case naming convention, things would have worked perfectly fine.
As a solution I wrote a custom naming convention which corrects the naming convention error when it has ID in the name and combines it with camelCase naming convention.
var createInconsistenIDConvention = function () {
var serverPropertyNameToClient = function (serverPropertyName, prop) {
if (prop && prop.isDataProperty && (prop.nameOnServer && prop.nameOnServer === "ID")) {
return "id";
} else {
var firstSection = serverPropertyName.substr(0, 1).toLowerCase();
var idSection = "";
if (serverPropertyName.substr(1).indexOf("ID") != -1) {
firstSection += serverPropertyName.substr(1, serverPropertyName.substr(1).indexOf("ID")).toLowerCase() + "Id";
} else {
firstSection += serverPropertyName.substr(1);
}
return firstSection;
}
}
var clientPropertyNameToServer = function (clientPropertyName, prop) {
if (prop && prop.isDataProperty && (prop.nameOnServer && prop.nameOnServer.indexOf("ID") != -1)) {
return prop.nameOnServer;
} else {
return clientPropertyName.substr(0, 1).toUpperCase() + clientPropertyName.substr(1);
}
}
return new breeze.NamingConvention({
name: "inconsistenID",
serverPropertyNameToClient: serverPropertyNameToClient,
clientPropertyNameToServer: clientPropertyNameToServer
});
};
Not sure if the way I've used nameOnServer property is not correct. I couldn't find any documentation on that in breeze website.
please note that the above code only consider situations like ID, CountryID, GameID, PersonID etc.
Problem solved for now.
I am trying to build a dynamic tree. I am getting my data from a C# WCF Service. It is returning me JSON data , but data is not reflecting in tree.
I am using EXTJS 4.
.Js Code -
Ext.require([
'Ext.tree.*',
'Ext.data.*',
'Ext.tip.*'
]);
Ext.onReady(function () {
Ext.QuickTips.init();
var store = Ext.create('Ext.data.TreeStore', {
proxy: {
type: 'ajax',
url: 'Services/InfographicsDataService.svc/GetTree'
},
root: {
text: 'Ext JS',
id: 'src',
expanded: true
},
reader: {
type: 'json',
root: 'd'
}
}); // End of store code
var tree = Ext.create('Ext.tree.Panel', {
store: store,
viewConfig:
{
plugins:{ ptype: 'treeviewdragdrop' }
},
renderTo: 'tree-div',
height: 300,
width: 250,
title: 'Files',
useArrows: true
}); // End of tree
}); // End of ready function
This is the code at my service end-::
[OperationContract]
[WebGet]
public List<TreeNode> GetTree()
{
List<TreeNode> nodes = new List<TreeNode>();
nodes.Add(new TreeNode() { id="src/ModelManager.js", text =
"ModelManager.js" });
nodes.Add(new TreeNode() { id="src/data", text = "data" });
nodes.Add(new TreeNode() { id="src/draw", text = "draw" });
return nodes;
}
Json returned by wcf service--
{"d":[
{
"__type":"TreeNode:#Infographics.Services.Model",
"id":"src\/ModelManager.js",
"leaf":false,
"text":"ModelManager.js"
},
{
"__type":"TreeNode:#Infographics.Services.Model",
"id":"src\/data",
"leaf":false,
"text":"data"
},
{
"__type":"TreeNode:#Infographics.Services.Model",
"id":"src \/draw",
"leaf":false,
"text":"draw"
}]
}
Call is going to server and returning the data but not adding nodes in tree
Page is showing just the root Extjs node.
Initially I thought , it is just root property of reader which I need to set to "d" , but there is something more I am missing.
Can somebody help me in finding what is that small mistake I am making ?
Can you change the store like this and try,
var store = Ext.create('Ext.data.TreeStore',
{
proxy:
{
type: 'ajax',
url: 'Services/InfographicsDataService.svc/GetTree',
reader:
{
type: 'json',
root: 'd'
}
},
root:
{
text: 'Ext JS',
id: 'src',
expanded: true
}
});