get is not defined when trying to extends JSONSerializer - serialization

I try to define my custom serializer by extending DS.JSONSerialzer.
I pick the serialize function without modifications but when i run Ember,i get this error:
ReferenceError: get is not defined
This is my code :
import DS from 'ember-data';
export default DS.JSONSerializer.extend({
serialize: function(record, options) {
var json = {};
if (options && options.includeId) {
var id = get(record, 'id');
if (id) {
json[get(this, 'primaryKey')] = id;
}
}
record.eachAttribute(function(key, attribute) {
this.serializeAttribute(record, json, key, attribute);
}, this);
record.eachRelationship(function(key, relationship) {
if (relationship.kind === 'belongsTo') {
this.serializeBelongsTo(record, json, relationship);
} else if (relationship.kind === 'hasMany') {
this.serializeHasMany(record, json, relationship);
}
}, this);
return json;
},
});
I didn't change any code. This is the original. Why get is suddenly undefined? It's imported in line 1 in the original file JSONSerialiser
Can you help me?

They have get defined in the scope when creating the serializer, but that doesn't extend outside of their scope into your files.
var get = Ember.get;
var isNone = Ember.isNone;
var map = Ember.ArrayPolyfills.map;
var merge = Ember.merge;
Either replace all of the get methods with Ember.get or define get to be Ember.get

Related

Angular-translate: Set custom loader option from controller

Today, I have an config for the translateProvider looking like this:
App.config(['$translateProvider', function ($translateProvider) {
$translateProvider.preferredLanguage('en-US');
$translateProvider.useLoader('TranslationLoader', { versionIdentifier : 127} );
$translateProvider.useMissingTranslationHandler('MissingTranslationHandler');
}]);
The problem is that I don't know the value of the formIdentifier-option at configuration time. I get this value after resolving the first state in ui-route. I've tried to set the translationProvides loader in the state's controller, but realized that that's not possible :)
Any ideas?
angular-translate allows you to use any service as a loader as long as it meets a desired interface. But it doesn't restrict you in ways of how you pass additional parameters to the loader. So, you may pass them just like you want.
For example, you can set additional parameters directly to the loader. Just implement setters for them on top of your loader:
module.factory('Loader', [
'$q',
function($q) {
var myParam;
var loader = function(options) {
var allParams = angular.extend({}, { myParam: myParam }, options);
var deferred = $q.defer();
// load stuff
return deferred.promise;
};
loader.setMyParam = function(param) {
myParam = param;
};
return loader;
}])
Also, you may try to set these parameters with some helper service (either sync or async:
module.factory('SyncLoader', [
'$q', '$injector',
function($q, $injector) {
var loader = function(options) {
var helper = $injector.get(options.helper);
var myParam = helper.getMyParam();
var deferred = $q.defer();
// load stuff
return deferred.promise;
};
return loader;
}]);
or
module.factory('AsyncLoader', [
'$q', '$injector',
function($q, $injector) {
var loader = function(options) {
var helper = $injector.get(options.helper);
var deferred = $q.defer();
helper.getMyParam()
.then(function success(myParam) {
// load stuff
}, function error() {
// fail, probably
});
return deferred.promise;
};
return loader;
}]);
Also, it might be possible to use events somehow. Or, maybe, there are some other ways possible. It depends on a specific architecture.

Is there any kind of wildcard operator in the Durandal observable plugin, to subscribe to a change in any property?

Is there any kind of wildcard operator in the Durandal observable plugin, as there is in (for example) JsObservable?
The Durandal observable documentation gives this example:
var observable = require('plugins/observable');
var viewModel:{
firstName:'',
lastName:''
};
observable(viewModel, 'firstName').subscribe(function(value){
console.log('First name changed.');
});
viewModel.firstName = 'Test';
What I'd like to do is use a wildcard to subscribe to any changed property on the target. Something like this:
observable(viewModel, '*').subscribe(function(property, value){
console.log(property + ' changed.');
});
I don't see anything in the API documentation, but wondered if there was anything undocumented, or if anyone has a workaround to implement this behaviour.
Unfortunately, there is no wildcard operator for this functionality.
But you can easily create wrapper module for this functionality.
Here is small example:
var observable = require('plugins/observable');
var wildcardObservable = function(obj, changeCallback){
for(var prop in obj){
observable(obj, prop).subscribe(changeCallback);
}
}
var changeCallback = function() {
console.log('property changed.');
}
Usage:
var viewModel:{
firstName:'',
lastName:''
};
wildcardObservable(viewModel, changeCallback);
With thanks to U10 for the start above, (and with reference to a few examples on the web) I came up with the following, which uses a closure to track all the necessary properties. It's a bit messy but it does what I need for now - hopefully it will be of use to someone.
var ChangeTracker = (function () {
function ChangeTracker() {
}
ChangeTracker.prototype._trackChange = function (prop, target) {
var type = typeof (target[prop]);
var value = target[prop];
_logger.log("_trackChange", { target: target, prop: prop, type: type, value: value }, "CT");
_obs(target, prop).subscribe(function (newValue) {
var obj = {
target: target,
prop: prop,
newValue: newValue,
oldValue: value
};
_logger.log(">>>>>>>>>>>>>>> CHANGE!", obj, "CT");
value = newValue;
});
};
ChangeTracker.prototype.TrackChanges = function (target) {
var _this = this;
for (var prop in target) {
if (target.hasOwnProperty(prop)) {
this._trackChange(prop, target);
}
var underlying = ko.utils.unwrapObservable(target[prop]);
if (underlying instanceof Array) {
ko.utils.arrayForEach(underlying, function (item) {
_this.TrackChanges(item);
});
} else if (typeof underlying === "object") {
this.TrackChanges(underlying);
}
}
}
};
return ChangeTracker;
})();

knockout search issue Property 'model' of object #<Object> is not a function

how can i get it work ?
define(['plugins/router', 'knockout', 'services/logger', 'durandal/app', 'mapping', 'services/routeconfig', 'services/dataBindingHandlers'], function (router, ko, logger, app, mapping, routeconfig, dataBindingHandlers) {
//#region Internal Methods
function activate() {
logger.log('Übersicht View Activated', null, 'newSearch', true);
return true;
}
//#endregion
//==jquery=================================================
function attached() {
}//-->end of attached()
var url = "https://www.googleapis.com/books/v1/volumes?q=the+Cat+In+The+Hat", path = $.getJSON(url);
path.then(function (data) {
console.log(data.items);
var viewModel = {
title: 'Overview',
query: ko.observable('')
};
viewModel.activate = activate();
viewModel.attached = attached();
viewModel.model = mapping.fromJS(data.items, {}, viewModel);
/*understanding ko.mapping.fromJS signature:knockoutjs.com/documentation/plugins-mapping.html
ko.mapping.fromJS(data) - this syntax will create view model.
ko.mapping.fromJS(data, mappingOptions) - this will create view model with particular options.
ko.mapping.fromJS(data, mappingOptions, viewModel) -
ko.mapping.fromJS(data, viewModel) -
ko.mapping.fromJS(data, {}, viewModel) - and this one convers your data without mapping options and put it to view model.
*/
viewModel.filteredItems = ko.computed(function () {
var search = this.query().toLowerCase();
alert("i'am here in viewModel.books computed");
console.log(viewModel.model);
return ko.utils.arrayFilter(this.model(), function (book) {
return book.id().toLowerCase().indexOf(search) >= 0 || book.kind().toLowerCase().indexOf(search) >= 0 || book.etag().toLowerCase().indexOf(search) >= 0
});
}, viewModel);
return viewModel;
});
});
Utility Functions in KnockoutJS
UPDATES: i recieve a loop of objects when i console.log(viewModel.model);
You haven't clearly stated what it is that doesn't work about it?
However, you probably need to add the activate and attached methods to the viewModel in order for them to be called by durandal.
viewModel.activate = activate;
viewModel.attached = attached;
You probably also intend this chunk of code to be called within the activate function and not in the define call:
var url = "https://www.googleapis.com/books/v1/volumes?q=the+Cat+In+The+Hat",path =$.getJSON(url);
path.then( function (data) {
var books = data.items;
console.log(books);

Durandal Custom View Location Strategy

I am trying to figure out how to use a custom view location strategy, I have read the documentation at this page http://durandaljs.com/documentation/Using-Composition/ but I don't exactly understand what the strategy function should look like.
Can anybody give me a quick example of what the implementation of this function would be like and the promise that returns (even a simple one) etc?
Thanks in advance,
Gary
p.s. This is the code in my html:
<div>
<div data-bind="compose: {model: 'viewmodels/childRouter/first/simpleModel', strategy:
'viewmodels/childRouter/first/myCustomViewStrategy'}"></div> </div>
and this is the code in my myCustomViewStrategy:
define(function () {
var myCustomViewStrategy = function () {
var deferred = $.Deferred();
deferred.done(function () { console.log('done'); return 'simpleModelView'; });
deferred.fail(function () { console.log('error'); });
setTimeout(function () { deferred.resolve('done'); }, 5000);
return deferred.promise();
};
return myCustomViewStrategy;
});
but I get the error:
Uncaught TypeError: Cannot read property 'display' of undefined - this is after done has been logged in the console window.
Okay I solved this by creating my custom view strategy by the following:
define(['durandal/system', 'durandal/viewEngine'], function (system, viewEngine) {
var myCustomViewStrategy = function () {
return viewEngine.createView('views/childRouter/first/sModelView');
}
return myCustomViewStrategy;
});
As I found the documentation a bit lacking on compose binding's strategy setting I checked the source code how it works. To summ it up:
The module specified by the compose binding's strategy setting by its moduleId
must return a function named 'strategy'
which returns a promise which results in the view to be bound
as a HTML element object.
As a parameter the strategy method receives the compose binding's settings object
with the model object already resolved.
A working example:
define(['durandal/system', 'durandal/viewEngine'], function (system, viewEngine) {
var strategy = function(settings){
var viewid = null;
if(settings.model){
// replaces model's module id's last segment ('/viewmodel') with '/view'
viewid = settings.model.__moduleId__.replace(/\/[^\/]*$/, '/view');
}
return viewEngine.createView(viewid);
};
return strategy;
});
Durandal's source:
// composition.js:485
for (var attrName in settings) {
if (ko.utils.arrayIndexOf(bindableSettings, attrName) != -1) {
/*
* strategy is unwrapped
*/
settings[attrName] = ko.utils.unwrapObservable(settings[attrName]);
} else {
settings[attrName] = settings[attrName];
}
}
// composition.js:523
if (system.isString(context.strategy)) {
/*
* strategy is loaded
*/
system.acquire(context.strategy).then(function (strategy) {
context.strategy = strategy;
composition.executeStrategy(context);
}).fail(function(err){
system.error('Failed to load view strategy (' + context.strategy + '). Details: ' + err.message);
});
} else {
this.executeStrategy(context);
}
// composition.js:501
executeStrategy: function (context) {
/*
* strategy is executed
* expected to be a promise
* which returns the view to be bound and inserted to the DOM
*/
context.strategy(context).then(function (child) {
composition.bindAndShow(child, context);
});
}

In an ExtJS Grid, how do I get access to the data store fields that are part of the sort set

How do I get access to the columns/datastore fields that are part of the sort set.
I am looking to modify the a grid's sort parameters for remote sorting. I need the remote sort param's sort key to match the column's field's mapping property. I need these things to happen though the normal 'column header click sorts the data' functionality.
Remote sorting and field mapping (ExtJS 4.1)
This functionality seems not to be implemented in ExtJS. Here is a solution using the encodeSorters function provided since ExtJS 4. Accessing fields map throught the model's prototype is a bit dirty but it does the job :
var store = Ext.create('Ext.data.Store', {
...,
proxy: {
...,
encodeSorters: function (sorters) {
var model = store.proxy.model,
map = model.prototype.fields.map;
return Ext.encode(Ext.Array.map(sorters, function (sorter) {
return {
property : map[sorter.property].mapping || sorter.property,
direction: sorter.direction
};
}));
}
}
});
However, it would be more relevant to override the original method :
Ext.data.proxy.Server.override({
encodeSorters: function(sorters) {
var min, map = this.model.prototype.fields.map;
min = Ext.Array.map(sorters, function (sorter) {
return {
property : map[sorter.property].mapping || sorter.property,
direction: sorter.direction
};
});
return this.applyEncoding(min);
}
});
Assuming you are using simpleSortMode, you could do something like this in your store.
listeners: {
beforeload: function( store, operation, eOpts ) {
if (store.sorters.length > 0) {
var sorter = store.sorters.getAt(0),
dir = sorter.direction,
prop = sorter.property,
fields = store.model.getFields(),
i,
applyProp = prop;
for (i = 0; i < fields.length; i++) {
if (fields[i].name == prop) {
applyProp = fields[i].mapping || prop;
break;
}
}
//clearing the sorters since the simpleSortMode is true so there will be only one sorter
store.sorters.clear();
store.sorters.insert(0, applyProp, new Ext.util.Sorter({
property : applyProp,
direction: dir
}));
}
}
},