EmberJS: Questionnaire:bind 2 checkboxes to same value, one of them Inverted - ember.js

im trying to implement a simple questionnaire component in EmberJS consisting of 10 different questions, where each additional question depends on the answer of the question before(maximum depth is 6) and appears after answering that. All of those questions are yes or no questions.
What i want now is 2 checkboxes/buttons, one representing yes, one representing no.
I know i could achieve that by having 2 computed properties for each question bound to the checkboxes and setting each other(even there im not quite sure,because of the opposite binding, how to make certain none of those is true by default, resulting in the next question being shown ), but i cant help but think that having 20 computed properties for this use case isnt the best way to do things
Any better and cleaner ideas for this problem are much appreciated!

Build a question component.
App.CQuestionComponent = Ember.Component.extend({
q: null,
isYes: false,
isNo: false,
result: null,
_yes: function() {
var isYes = this.get('isYes');
if ( isYes ) {
this.removeObserver('isNo', this, '_no');
this.set('isNo', ! isYes);
this.addObserver('isNo', this, '_no');
this.set('result', true);
} else {
this.set('result', null);
}
}.observes('isYes'),
_no: function() {
var isNo = this.get('isNo');
if ( isNo ) {
this.removeObserver('isYes', this, '_yes');
this.set('isYes', ! isNo);
this.addObserver('isYes', this, '_yes');
this.set('result', false);
} else {
this.set('result', null);
}
}.observes('isNo'),
});
http://emberjs.jsbin.com/sifewitahu/1/edit?html,js,output

Related

Get Index Number of a element in the List

Iam creating a quiz App in flutter , to find whether the currect answer is selected i want to get the index number of the selected button, i doesnt know whether it is a correct approach to check the correct answer.Please help me how to get the index number when user presses the answer.
{'questionText': "What is your name",
'answers':['honest','devika','monisha','khyathy'],
'correctAnswer':'3',
},
{'questionText': "What is your Mobile Name",
'answers':['Iphone','Huawei','Applele','SAMSUNG'],
'correctAnswer':'2',
},
];
void answered(){
//find the index of the selected answer
final result = (questions[questionIndex ]['answers']indexOf());
if (result== ) {
print(result);
} `
Iam calling this List in a raised button in below code:
...(questions[questionIndex]['answers'] as List<String>).map((answer) {
return ReusableButton(
child: Text(answer),
onPressed:() =>[currentQuestion(),answered()],
color: Colors.green,
);
}).toList(),`
I think that you could just make 'correctAnswer' not the index of the answer but the answer itself, so you rather check the two string instead of checking indexes.
It should look like this.
{'questionText': "What is your name",
'answers':['honest','devika','monisha','khyathy'],
'correctAnswer':'khyathy',
},
{'questionText': "What is your Mobile Name",
'answers':['Iphone','Huawei','Applele','SAMSUNG'],
'correctAnswer':'Applele',
},
];
void answered(answer){
final result = (questions[questionIndex ]['correctAnswer']);
if (result == answer) {
print(result);
} `
I think that's right, it's my first answer in stack overflow so to all the OGs feel free to correct me.
If you want to check indexes you could use this.
{'questionText': "What is your name",
'answers':['honest','devika','monisha','khyathy'],
'correctAnswer':'3',
},
{'questionText': "What is your Mobile Name",
'answers':['Iphone','Huawei','Applele','SAMSUNG'],
'correctAnswer':'2',
},
];
void answered(answer){
final result = (questions[questionIndex ]['correctAnswer']);
final answerIndex = questions[questionIndex]['answers'].indexOf(answer).toString()
if (result == answerIndex) {
print(result);
}
...(questions[questionIndex]['answers'] as List<String>).map((answer) {
return ReusableButton(
child: Text(answer),
onPressed:() =>[currentQuestion(),answered(answer)],
color: Colors.green,
);
}).toList(),`
This should do it, I don't know what your questionIndex function does because you didn't post it so I assumed it returns an int value of the index of the current question.
Also, I don't know if you noticed but in your question, you wrote:
final result = (questions[questionIndex ]['answers']indexOf());
indexOf is a list built-in method so when you call it on a list you have to put a dot before it like so:
final result = (questions[questionIndex ]['answers'].indexOf(itemYouWantTheIndex));
There is also another error when you check the validity of the answer but I think it is just because you didn't know how to compare.
Tell me if my answer satisfied you, I'd be really happy if it did.

Google Sheets Script - If or statement. Restrict onEdit to specific sheet

Super quick question. I have this function I want to run on entire workbook, except two specific sheets.
This is my code:
function onEdit(e) {
var sheet = SpreadsheetApp.getActiveSheet();
if (sheet.getName() != "Total" || sheet.getName() != "DataRange" ) {
someAction();
}
}
This just does not work, the code runs on all sheets no matter what. This is probably a noob question but.
not an "answer" as you already answered your own question, but an alternative:
I'll prefer to use an indexOf I found that (in this case) clearer thant the switch:
function onEdit(e) {
var sheet = SpreadsheetApp.getActiveSheet();
if (["Total","DataRange"].indexOf(sheet.getName()) == -1 ) {
someAction();
}
}
I just identify in an array all the sheet that I want to avoid and then check that the current sheet is not one of then (return -1)
I solved it by using switch instead
switch (sheet.getName()) {
case "Total":
return;
case "DataRange":
return;
default:
doSomething();
break;
}
Answer by Kenny Bones moved from question to answer space.

Emberjs: best way to iterate through ArrayProxy content?

Often, I need to loop through an Ember.ArrayProxy object's content.
Exemple 1, I need to build a list of IDs:
var loc = myArrayProxy.get('length') || 0,
ids = new Array(),
idsList;
while(--loc >= 0) {
var curObject = myArrayProxy.objectAt(loc);
ids.push(curObject.id);
}
idsList = ids.join(',');
Exemple 2, I need to build an Array of primitive objects (not Ember.Object):
var loc = myArrayProxy.get('length') || 0,
newContent = new Array();
while(--loc >= 0) {
var curObject = myArrayProxy.objectAt(loc);
newContent.push({
id: curObject.id,
name: curObject.name
});
}
Question: is there a better way to do this? The "while(--loc >= 0)" seems bad to me.
Ember.ArrayProxy provides many friendly functions (through Ember.Array, Ember.Enumerable, ...). Loops can often be avoided using "forEach". In your 2nd example, you may consider using "map".
Here is a link to Ember.ArrayProxy documentation.
Be sure to look at: Ember.Array and Ember.Enumerable
edit:
For instance, assuming the order of the ids is not relevant, your first example could be written:
var idsList = myArrayProxy.mapProperty('id').join(',');

Why is the computed property being updated even though I didn't specify its dependencies?

I have a schema structured something like this:
App = {};
App.Outer = Ember.Object.extend({
inner: null,
quantity: 0,
count: function () {
var self = this, inner = self.get('inner');
return self.get('quantity') * inner.get('count');
}.property('nothing')
});
App.Inner = Ember.Object.extend({
count: 0
});
Yes, the 'count' computed property really is set to depend on a totally nonexistent property 'nothing'. However it seems to get updated anyway:
var o1 = App.Outer.create({
quantity: 2,
inner: App.Inner.create({count: 4})
});
console.log(o1.get('count')); // => 8
o1.get('inner').set('count', 5);
console.log(o1.get('count')); // => 10
o1.set('inner', App.Inner.create({count: 10}));
console.log(o1.get('count')); // => 20
Am I missing something? It knows what to update without me telling it what to depend on... can't be right, can it? What am I misunderstanding about Ember computed properties?
Thanks
By using this.get('quantity'), inner.get('count') you are telling it what it depends on. Every time you call .get('count') the function will go off and get the current values for those properties and therefore return the up to date result.
The .property() part comes into play when you bind the computed property count to something else e.g. a view. When you do that then making a change to quantity will automatically recalculate the count, and this new value will be propagated to whatever you have bound the count too.
You can see the difference in action here: http://jsfiddle.net/tomwhatmore/6gz8x/
As of Ember 0.9.5, property values are not cached unless cacheable() is called on them. e.g.
...
count: function () {
var self = this, inner = self.get('inner');
return self.get('quantity') * inner.get('count');
}.property('nothing').cacheable()
...
For more background, see the discussion on this GitHub issue: https://github.com/emberjs/ember.js/issues/38

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')