I'm retrieving a json and want to use a field(don't know the right term) in the json to initialize backbone model after fetch.
It seems I have to implement parse function, but how?
1) You need to define defaults object on your model setting up properties you want to populate from a request; 2) then you need to filter (those) necessary fields and construct new object in the model's parse method:
var model = Backbone.Model.extend({
defaults: {
swordType: null
},
parse: function(data) {
// filter what you need
var swordTypeValue = null;
if(data.hasOwnProperty('swordType')) {
swordTypeValue = data.swordType;
}
// construct attributes from it
return { swordType: swordTypeValue };
}
});
Related
i'm using breezejs for some time now, and i'm happy about it and it's rich functionality , but the problem with breezejs is that i cant use it as datasource almost for anything.
there is no grid that you could show data and not losing functionality, and you cant use your array of entities as normal array. (so you cant use it as datasource for dropdown ...)
so for showing data in UI i end up converting data to normal array and losing Breeze functionality (like track change) and before save converting them back.
some code like this one for converting to normal array:
if(data.length>0)
{
var names = Object.getOwnPropertyNames(data[0]._backingStore);
var columns: string[] = [];
for (var i = 0; i < names.length; i++)
{
columns.push(names[i]); //Getting columns name
}
var newArray = [];
data.forEach((item, index, array) => {
newArray.push(item._backingStore);
});
}
my question is how do you show your data in UI using breezejs properly?
(i'm using angualr (hottowel))
Assuming you're trying to solve issues like this:
The grid doesn't like the entityType and entityAspect properties on Breeze entities.
This grid doesn't know how to handle Knockout style "properties" that are functions.
Creating a POCO object using the Breeze entity's property values disconnects you from the change tracking goodness.
You could try creating your POCO object using Object.defineProperty, using the Knockout observable as the property's getter and setter functions. Here's a simple example:
Typescript + Knockout:
class PocoBreezeEntity {
constructor(private entity: breeze.Entity) {
entity.entityType.dataProperties.forEach(
dataProperty => {
Object.defineProperty(
this,
dataProperty.name,
{
get: entity[dataProperty.name],
set: entity[dataProperty.name],
enumerable: true,
configurable: true
});
});
}
}
Typescript + Angular:
class PocoBreezeEntity {
constructor(private entity: breeze.Entity) {
entity.entityType.dataProperties.forEach(
dataProperty => {
Object.defineProperty(
this,
dataProperty.name,
{
get: function() { return entity[dataProperty.name]; },
set: function(newValue) { entity[dataProperty.name] = newValue; },
enumerable: true,
configurable: true
});
});
}
}
With this kind of approach you have the benefits of POCO entities without losing the Breeze change tracking.
I can execute a query in breeze from the server (using EF) which returns a load of boostrap data thus:
em.executeQuery(_lookupsQuery).then(function (data) {
_lookups = data.results;
console.log(_lookups[0].currentUserId);
This returns currentUserId which is a guid. I then store em using local storage for querying locally later:
_lookups = [{
currentUserId: em.executeQueryLocally(_lookupsQuery.toType(breeze.DataType.String))
}];
However this does not work as it requires an entity type e.g:
em.executeQueryLocally(_lookupsQuery.toType(em.metadataStore.getEntityType("Measure")))
Since currentUserId is a guid I am not sure which type to cast the query to. I have tried to make an entity type on the client just for this but it does not seem to work. Any help on solving this would be appreciated.
Edit:
After a suggestion, I modified lookups:
[HttpGet]
public async Task<object> Lookups()
{
var currentUser = await UserManager.FindById(Guid.Parse(User.Identity.GetUserId()));
var companyId = currentUser.CompanyId.Value;
return new
{
currentUser = new
{
Id = currentUser.Id
}
};
}
When querying remotely using:
em.executeQuery(_lookupsQuery).then(function (data) {
_lookups = data.results;
console.log(_lookups[0].currentUser);
I get:
Object { id="f2dceb4b-29e7-4533-99e2-2052dc39143a"}
I set up the new entity type:
metadataStore.addEntityType({
shortName: "CurrentUser",
dataProperties: {
id: { dataType: "String", isPartOfKey: true }
}
});
but when I query locally:
_lookups = [{
currentUser: em.executeQueryLocally(_lookupsQuery.toType(em.metadataStore.getEntityType("CurrentUser"))) }];
console.log(_lookups[0].currentUser);
this returns []
What am I doing wrong?
There are a few ways you can handle it. I am only going to touch on the two most basic methods that I personally use and hopefully one sparks your interest.
-1. Create an entityType in your metadataStore for user-type information.
metadataStore.addEntityType({
shortName: "User",
dataProperties: {
userId: { dataType: "String", isPartOfKey: true },
userName: { dataType: "String" }
}
});
This will add an entity type that you can serialize your return results to. It is important to note here that if you change anything about that user without accepting changes locally it will try to save it next time you call saveChanges() so make sure you handle those situations if applicable.
Of course that isn't the only option. You can most certainly just grab that user id from the query results without Breeze ever knowing about it or what it is for.
-2. POJO
function user(data) {
var self = this;
self.UserId = data.userId;
self.UserName = data.userName;
}
// After your query returns data
query.execute().then(userReturned);
function userReturned(data) {
// data is the returned object, which contains
// an httpResponse which is what breeze returns
// as the raw response
new user(data.httpResponse.data);
}
This method basically just grabs the httpResponse when the promise returns and uses it to create a Plain Old JavaScript Object without Breeze knowing about it. Of course for this to work you need to examine your data object that is returned and find what you are looking for and serialize that.
Edit
Your query locally should look like this -
query = breeze.entityQuery().from("Whatever").toType("CurrentUser").executeLocally();
em.executeQueryLocally(query);
Problem
I have a view with 6 drop downs. Each of which is being populated by a Web API call. I want
to use breeze to run the query locally once it has populated from the remote server
The code runs fine when the data call is against the server. The issue is when trying to query the local cache. I never get any results returned. Is my approach flawed or am I doing something wrong ?
SERVER SIDE
View model
class genericDropDown()
{
public int value{get;set;}
public string option{get;set;}
}
The WebAPI [A single sample method]
[HttpGet]
// GET api/<controller>
public object GetSomeVals()
{
return _context.getClinician();
}
The Repository [A single sample method]
public IEnumerable<genericDropDown> getDropDownVal()
{
return context.somemodel(a=>new{a.id,a.firstname,a.lastname}).ToList().
Select(x => new GenericDropDown
{ value = x.id, option = x.firstname+ " " + x.lastname});}
}
CLIENT SIDE
Datacontext.js
var _manager = new breeze.EntityManager("EndPoint");
//Being called from my view model
var getDropDownBindings = function(KO1, KO2) {
//First add the entity to the local metadatastore then populate the entity
$.when(
addDD('clinicianDropDown', webAPIMethod),
getData(KO1, webAPIMethod, null, 'clinicianDropDown'),
addDD('docTypeDropDown', webAPIMethod);
getData(KO2, webAPIMethod, null, 'docTypeDropDown'),
).then(querySucceeded).fail(queryFailed);
function querySucceeded(data) {
logger.log('Got drop down vals', "", 'dataContext', true);
}
};
//Add the entity to local store. First param is typename and second is
resource name (Web API method)
var addDD = function(shortName,resName) {
_manager.metadataStore.addEntityType({
shortName: shortName,
namespace: "Namespace",
autoGeneratedKeyType: breeze.AutoGeneratedKeyType.Identity,
defaultResourceName:resName,
dataProperties: {
value: { dataType: DataType.Int32,
isNullable: false, isPartOfKey: true },
option: { dataType: DataType.String, isNullable: false }
}
});
return _manager.metadataStore.registerEntityTypeCtor(shortName, null, null);
};
//Get the data
var getData = function(observableArray, dataEndPoint, parameters, mapto) {
if (observableArray != null)
observableArray([]);
//TO DO: Incorporate logic for server or local call depending on
// whether this method is accessed for the first time
var query = breeze.EntityQuery.from(dataEndPoint);
if (mapto != null && mapto != "")
query = query.toType(mapto);
if (parameters != null)
query = query.withParameters(parameters);
//This approach doesnt work on local querying as Jquery complains
//there is no 'then' method. Not sure how to implement promises
//when querying locally
/* return _manager.executeQuery(query).then(querySucceeded).fail(queryFailed);
function querySucceeded(data) {
if (observableArray != null)
observableArray(data.results);
}
*/
//The array length from this query is always 0
var data = _manager.executeQueryLocally(query);
observableArray(data.results);
return;
};
//Generic error handler
function queryFailed(error) {
logger.log(error.message, null, 'dataContext', true);
}
viewmodel.js
//In Durandal's activate method populate the observable arrays
dataContext.getDropDownBindings (KO1,KO2);
Viewmodel.html
<select class="dropdown" data-bind="options: KO1, optionsText: 'option', value: 'value', optionsCaption: 'Clinicians'"></select>
<select class="dropdown" data-bind="options: KO2 optionsText: 'option', value: 'value', optionsCaption: 'Document Types'"></select>
You can only execute local queries against types that are described by metadata.
Without more information I can't be sure, but my guess is that your GetSomeVals method is not returning 'entities' but just loose data. In other words, the types of objects returned from the GetSomeVals method must be entities (or contain entities within a projection) in order for breeze to be able to perform a local query. This is because Breeze knows how to cache and query entities but has no ideas how to cache 'arbitrary' query results.
Note that you can return an anonymous type containing entities of different types from the server, (in order to populate mostly static small datasets), but the individual items must be 'entities'. In this case, Breeze will take apart the anon result and pick out any entities to include in the EntityManager cache.
Per you question of how to perform an local query with promises, use the FetchStrategy.FromLocalCache with the using method.
i.e. this query
var results = em.executeQueryLocally(query)
can also be expressed as:
query = query.using(FetchStrategy.FromLocalCache);
return em.executeQuery(query).then(data) {
var results = data.results;
}
The local query is still executed synchonously but is made to look async.
I am trying to reuse the same form for adding and editing employee information. I am using knockout js and on my view I make the knockout model:
var koModel = new EmployeeModel(div);
and if I want to populate the fields from the server I want to do something like this:
var koModel = new EmployeeModel(unserializedModelFromController, div);
I was wondering what is the best way to distinguish if the request is for a new employee or if it is to edit an existing employee.
If you turn your parameters around you can write a single constructor function.
var EmployeeModel = function(div, model) {
if (model) {
// Existing model has been passed, it's an edit request
} else {
// No model has been passed, it's a new request
}
}
This can be called like:
new EmployeeModel(div);
or
new EmployeeModel(div, model);
You can send a parameter with a default value to the view.
If you are editing an employee, you can send the value of id, you're creating not send.
The function that receives a request to store or edit could have a default value.
public void SaveOrEditEmployee(int id=0, ...) //id=0 is a default value
{
if(id==0)
{
//SaveEmployee
}else
{
//EditEmployee
Employee empl = (x => employee.id == id);
...
}
}
Or you can do likewise, receive full model and assess whether the property 'id' already exists in your database
I am trying to post data in JSON format to a .NET MVC Controller like this.
$.ajax({
type: 'POST',
url: 'http://mvc.tester.local/Home/NameConverter',
data: JSON.stringify({ convertermodel.InputName: obj.currentTarget.value }),
contentType: 'application/json'
});
But Javascript complains about the JSON.Stringify() bit.
The convertermodel.InputName to be exact.
The thing is I actually need this JSON data name to be that way i.e. have the same name as a property in my model; in order to take advantage of reflection for automatic binding.
This is my model:
public class NamesViewModel
{
public NameConverterModel convertermodel = new NameConverterModel();
}
and the sub Class
public class NameConverterModel
{
private string _inputName = "";
public string InputName
{
get { return _inputName; }
set { _inputName = value; }
}
}
How can I solve this please ?
I hope I am clear enough.
You would need your JSON to be of the structure like this:
{"convertermodel" : {
"InputName" : obj.currentTarget.value
}
}
Your JSON representation of your object needs to reflect the appropriate nesting that your object model that you're trying to model in the client-side requires. So defining your JSON by nesting your hierarchy at one level won't work -- you need to create objects of objects like you did in your C# code.