Ember Calling method inside the controller - ember.js

here is my code I have to call another method inside the Ember controller
I was tried but this is not working I have confused in this...
please help me to what is wrong in this code?
export default Ember.Controller.extend({
....
getValue(){
var a = 7 * 2;
return a;
},
getResult(){
var result = this.getValue(); // result is this.getValue is not function
}
});

First this code does not makes sense:
getValue(){
var a = a * 2;
return a;
},
here you're using a before you declare it.
but to answer your question: your code is correct.
Here is a working example. I've just replaced var a = a * 2; by var a = 7 * 2; to make this code valid.

My assumption is that whatever is calling getResult() is not setting the context of this to the controller, and my hunch is that you'll need to put getResults() in the actions object.

Related

Multiple Promises in Ember won't resolve in the template

I'm stuck trying to return the value of a bunch of promises.
To explain the situation: there are 4 models - the students in a group have a score for each objective.
So I've made a component into which I pass an objective and the group. The component then handles the requests to the store to look up each student's score for that objective, and return the average.
The code seems to work, the console.logs give me exactly what I want, right up to the end, but the promises won't resolve into the template - I get the { object Object }, which I believe is the unresolved promise.
Something I'm missing here? Is there an extra step needed when waiting for multiple promises to resolve?
I appreciate this is a little specific, when I understand the answer I'll try and rephrase the question.
Component Code:
averageScore: Ember.computed(function(){
var students = this.get('group.students');
var objective = this.get('objective');
var store = this.get('store');
var _this = this;
// Create an array of promises of each student's scores
var promises = [];
students.forEach((student) => {
var studentId = student.get('id');
var objectiveId = objective.get('id');
var newPromise = store.queryRecord('snapscore', { 'student' : studentId, 'objective': objectiveId });
promises.pushObject(newPromise);
});
// When promises resolve, find and return the average
return Ember.RSVP.allSettled(promises).then(function(scores){
let scoreTotal = 0;
let scoreCount = scores.length;
console.log("Score count is " + scoreCount);
scores.forEach((score)=>{
console.log("Student's score is " + score.value.get('score'));
scoreTotal = scoreTotal + score.value.get('score');
});
console.log("ScoreTotal is " + scoreTotal);
var average = scoreTotal/scoreCount;
console.log(average);
console.log(typeof(average));
return average;
});
}),
The component's template then simply returns averageScore.
Thanks
Computed property is not promise aware. So don't return the Promise inside computed property and generally don't do any set inside computed property.
In your case, you can have property named averageScore and do write your code in any of the component life cycle hook methods.(may be init or didReceiveAttrs hook). You can set the result to averageScore property this.set('averageScore',result).
If you still want to make computed property to promise aware then follow this ember igniter link

Change value of parameter in NSubstitute

I have this method to mock with NSubstitute:
public T VoerStoredProcedureUit<T>(string naam, params SqlParameter[] parameters)
The test method using it sends 2 SqlParameters to this method. VoerStoredProcedureUit is supposed to change the values of these parameters so the tested method can extract that.
I created the following with NSubstitute:
SqlParameter[] param =
{
new SqlParameter("#pat_id", SqlDbType.BigInt) {Direction = ParameterDirection.Output, Value = "Melding"},
new SqlParameter("#Melding", SqlDbType.VarChar, 4096) {Direction = ParameterDirection.Output, Value = 2}
};
productieVerbinding.VoerStoredProcedureUit<PatientNieuwResultaat>(Arg.Any<string>(),
Arg.Any<SqlParameter[]>()).ReturnsForAnyArgs(x =>
{
x[1] = param;
return PatientNieuwResultaat.Succes;
});
The setup however rises an exception:
A first chance exception of type 'NSubstitute.Exceptions.ArgumentIsNotOutOrRefException' occurred in NSubstitute.dll
Additional information: Could not set argument 1 (SqlParameter[]) as it is not an out or ref argument.
How do you return a value if the method uses implicitly by reference values?
If I understand your question correctly, you're trying to return the contents of param when VoerStoredProcedureUit<PatientNieuwResultaat> is called.
In ReturnsForAnyArgs, x[1] refers to the second parameter which is an SqlParameter[]. This isn't a ref/out parameter so you can't reassign it in the caller, which is why you get an error. Instead, you need to copy the elements from your template, into the supplied array. Something like this:
productieVerbinding.VoerStoredProcedureUit<PatientNieuwResultaat>(Arg.Any<string>(),
Arg.Any<SqlParameter[]>()).ReturnsForAnyArgs((x) =>
{
for (int i = 0; i < param.Length; i++)
{
((SqlParameter[])x[1])[i] = param[i];
}
return PatientNieuwResultaat.Succes;
});
You could obviously remove the for loop, since you know how many parameters you need to copy...
productieVerbinding.VoerStoredProcedureUit<PatientNieuwResultaat>(Arg.Any<string>(),
Arg.Any<SqlParameter[]>()).ReturnsForAnyArgs((x) =>
{
((SqlParameter[])x[1])[0] = param[0];
((SqlParameter[])x[1])[1] = param[1];
return PatientNieuwResultaat.Succes;
});
I found a working solution. Assigning a new variable to the parameters did't work somehow, but changing them does. Also, the second of the method parameter is an array, so it should be treated as such.
productieVerbinding.VoerStoredProcedureUit<PatientNieuwResultaat>(Arg.Any<string>(),
Arg.Any<SqlParameter[]>()).ReturnsForAnyArgs(x =>
{
paramPatId = ((SqlParameter[])x[1])[0];
paramMelding = ((SqlParameter[])x[1])[1];
paramPatId.Value = (long)2;
paramMelding.Value = "Melding";
return PatientNieuwResultaat.Succes;
});

Intersection of promises and dependent computed properties

I have a user model which has 2 relations (myFriends and friendsWithMe). The intersection is the Array of users which represents the real friends. I have solved this Computatation with RSVP.all :
friends: function() {
var ret = [];
Ember.RSVP.all([this.get('myFriends'), this.get('friendsWithMe')]).then(function(results) {
ret.pushObjects(_.intersection(results[0].get('content'), results[1].get('content'))) ;
});
return ret;
}.property('myFriends.#each', 'friendsWithMe.#each'),
The Problem is now I have another computed property that depends on this one:
/**
* Gives the relation between two User
* 4: has requested your friendship
* 3: Yourself
* 2: Friends
* 1: FriendShip Request
*/
myFriendshipStatus: function() {
if(this.get('friends').contains(this.container.lookup('user:current'))){
return 2;
} else if(this.get('friendsWithMe').contains(this.container.lookup('user:current'))){
return 4;
} else if(this.get('myFriends').contains(this.container.lookup('user:current'))){
return 1;
} else if (this.get('id') === this.container.lookup('user:current').get('id')){
return 3;
} else {
return 0;
}
}.property('friends.#each')
When I now debug myFriendShipStatus the promises are not resolved and the "friends" array has no entries yet.
I have also tried to change my friends function to the ember.computed.intersect, which would then look like this:
friends: function() {
return Ember.computed.intersect('myFriends', 'friendsWithMe')
}.property('myFriends.#each', 'friendsWithMe.#each'),
But then I get an exception from this line:
if(this.get('friends').contains(this.container.lookup('user:current'))){
Because the ArrayComputedProperty has no function contains.
How can get my friends function together with myFriendShipStatus working? I would prefer to use Ember.computed.intersect, but I don't know how I check then for it's values.
The reason it returns an empty array in the first example is as follows. Immediately after the Ember.RSVP.all() call, the return statement will be executed, returning an empty ret array. At some point in the future the RSVP promise will fulfill, but since the friends function has already returned the empty array, this will have no effect.
Here is what you could do:
// See http://emberjs.com/api/#method_A
friends: Ember.A,
recalculateFriends: function() {
Ember.RSVP.all([this.get('myFriends'), this.get('friendsWithMe')]).then(function(results) {
var myFriends = results[0], friendsWithMe = results[1];
this.set('friends', _.intersection(myFriends.get('content'), friendsWithMe.get('content')));
});
}.property('myFriends', 'friendsWithMe'), // #each is redundant here
myFriendshipStatus: function() {
// Will be recalculated when the friends array changes (which will in turn recalculate when myFriends or friendsWithMe changes
}.property('friends'),
And... I'm just now noticing you're using Ember.computed.intersect wrong :P It shouldn't be wrapped inside a function:
friends: Ember.computed.intersect('myFriends', 'friendsWithMe')
(See example: http://emberjs.com/api/#method_computed_intersect),

Pass variables to ember handlebars

I have an Ember.js ArrayController and some handlebar code that looks like this
<p>{{length}} {{pluralize length "thing"}}</p>
Then I've got a handlebar helper that looks like
Handlebars.registerHelper('pluralize', function(count, str){
debugger;
return (count > 1 ? str+"s" : str);
}
);
When the debugger breaks I observe seeing that count = 'length' not a number like I would expect.
So what gives? What's the correct way to accomplish my obvious task.
Working fiddle here. http://jsfiddle.net/MwTuw/2/
The trick is to use Ember.registerBoundHelper which passes all the relevant data as a final argument to the function.
Ember.Handlebars.registerBoundHelper('pluralize', function (count) {
var options = Array.prototype.pop.call(arguments);
var string = options.data.properties[1];
return (count > 1 ? string+"s" : string);
});
This removes the {{if controller.length}} hack that is required with the other solution and means that adding or removing additional objects will update the value accordingly.
How about this:
Ember.Handlebars.registerHelper('pluralize', function (property, options) {
var count = Ember.Handlebars.get(this, property, options);
var _options = options;
count = parseInt(count, 10); //to be sure ...
if (count > 1) {
_options = _options.concat('s');
}
return new Handlebars.SafeString(_options);
});
EDIT
Here is a working fiddle
EDIT 2
Here is your working updated fiddle
Basically the problem was that the handlebar helper was acting when the controller still had no records, I've added a if helper to the template that listen on the controller.length and fires when it changes and so invoking also the handlebar helper to parse the value.
Hope it helps
Using Ember.registerBoundHelper will make all the key-value pairs in the template available as an hash on the 2nd parameter of the helper:
Handlebars template:
{{orderShow dataOrderBy key1="value1" key2="value2" ... keyN="valueN"}}
Javascript:
Ember.Handlebars.registerBoundHelper('orderShow', function(order, options) {
if(options) {
for(var prop in options.hash) {
alert(prop + '="' + options.hash[prop] + '"')
}
}
return order;
}
This behaviour is described at the end of the following page: http://handlebarsjs.com/expressions.html

Reflection on EmberJS objects? How to find a list of property keys without knowing the keys in advance

Is there a way to retrieve the set-at-creations properties of an EmberJS object if you don't know all your keys in advance?
Via the inspector I see all the object properties which appear to be stored in the meta-object's values hash, but I can't seem to find any methods to get it back. For example object.getProperties() needs a key list, but I'm trying to create a generic object container that doesn't know what it will contain in advance, but is able to return information about itself.
I haven't used this in production code, so your mileage may vary, but reviewing the Ember source suggests two functions that might be useful to you, or at least worth reviewing the implementation:
Ember.keys: "Returns all of the keys defined on an object or hash. This is useful when inspecting objects for debugging. On browsers that support it, this uses the native Object.keys implementation." Object.keys documentation on MDN
Ember.inspect: "Convenience method to inspect an object. This method will attempt to convert the object into a useful string description." Source on Github
I believe the simple answer is: you don't find a list of props. At least I haven't been able to.
However I noticed that ember props appear to be prefixed __ember, which made me solve it like this:
for (f in App.model) {
if (App.model.hasOwnProperty(f) && f.indexOf('__ember') < 0) {
console.log(f);
}
};
And it seems to work. But I don't know whether it's 100% certain to not get any bad props.
EDIT: Adam's gist is provided from comments. https://gist.github.com/1817543
var getOwnProperties = function(model){
var props = {};
for(var prop in model){
if( model.hasOwnProperty(prop)
&& prop.indexOf('__ember') < 0
&& prop.indexOf('_super') < 0
&& Ember.typeOf(model.get(prop)) !== 'function'
){
props[prop] = model[prop];
}
}
return props;
}
Neither of these answers are reliable, unfortunately, because any keys paired with a null or undefined value will not be visible.
e.g.
MyClass = Ember.Object.extend({
name: null,
age: null,
weight: null,
height: null
});
test = MyClass.create({name: 'wmarbut'});
console.log( Ember.keys(test) );
Is only going to give you
["_super", "name"]
The solution that I came up with is:
/**
* Method to get keys out of an object into an array
* #param object obj_proto The dumb javascript object to extract keys from
* #return array an array of keys
*/
function key_array(obj_proto) {
keys = [];
for (var key in obj_proto) {
keys.push(key);
}
return keys;
}
/*
* Put the structure of the object that you want into a dumb JavaScript object
* instead of directly into an Ember.Object
*/
MyClassPrototype = {
name: null,
age: null,
weight: null,
height: null
}
/*
* Extend the Ember.Object using your dumb javascript object
*/
MyClass = Ember.Object.extend(MyClassPrototype);
/*
* Set a hidden field for the keys the object possesses
*/
MyClass.reopen({__keys: key_array(MyClassPrototype)});
Using this method, you can now access the __keys field and know which keys to iterate over. This does not, however, solve the problem of objects where the structure isn't known before hand.
I use this:
Ember.keys(Ember.meta(App.YOUR_MODEL.proto()).descs)
None of those answers worked with me. I already had a solution for Ember Data, I was just after one for Ember.Object. I found the following to work just fine. (Remove Ember.getProperties if you only want the keys, not a hash with key/value.
getPojoProperties = function (pojo) {
return Ember.getProperties(pojo, Object.keys(pojo));
},
getProxiedProperties = function (proxyObject) {
// Three levels, first the content, then the prototype, then the properties of the instance itself
var contentProperties = getPojoProperties(proxyObject.get('content')),
prototypeProperties = Ember.getProperties(proxyObject, Object.keys(proxyObject.constructor.prototype)),
objectProperties = getPojoProperties(proxyObject);
return Ember.merge(Ember.merge(contentProperties, prototypeProperties), objectProperties);
},
getEmberObjectProperties = function (emberObject) {
var prototypeProperties = Ember.getProperties(emberObject, Object.keys(emberObject.constructor.prototype)),
objectProperties = getPojoProperties(emberObject);
return Ember.merge(prototypeProperties, objectProperties);
},
getEmberDataProperties = function (emberDataObject) {
var attributes = Ember.get(emberDataObject.constructor, 'attributes'),
keys = Ember.get(attributes, 'keys.list');
return Ember.getProperties(emberDataObject, keys);
},
getProperties = function (object) {
if (object instanceof DS.Model) {
return getEmberDataProperties(object);
} else if (object instanceof Ember.ObjectProxy) {
return getProxiedProperties(object);
} else if (object instanceof Ember.Object) {
return getEmberObjectProperties(object);
} else {
return getPojoProperties(object);
}
};
In my case Ember.keys(someObject) worked, without doing someObject.toJSON().
I'm trying to do something similar, i.e. render a generic table of rows of model data to show columns for each attribute of a given model type, but let the model describe its own fields.
If you're using Ember Data, then this may help:
http://emberjs.com/api/data/classes/DS.Model.html#method_eachAttribute
You can iterate the attributes of the model type and get meta data associated with each attribute.
This worked for me (from an ArrayController):
fields: function() {
var doc = this.get('arrangedContent');
var fields = [];
var content = doc.content;
content.forEach(function(attr, value) {
var data = Ember.keys(attr._data);
data.forEach(function(v) {
if( typeof v === 'string' && $.inArray(v, fields) == -1) {
fields.push(v);
}
});
});
return fields;
}.property('arrangedContent')