How to pass the ng-model into a function instead of ng-model's value? - angularjs

I want to create a single function that will be used for total project.
It will work based on the ng-model passed into it.
For ex:-
$scope.checkBoxValueChanged=function(model) {
if($scope.model=="AA") {
$scope.model="BB";
}
else {
$scope.model="BB";
}
};
});
If i have the passed model's value as "AA" then i need to assign the passed model's value as "BB"
But what i am getting is the model value instead of model name.
Can anyone tell me how to get the model instead of model value.
Any help will be highly appreciated.

You should pass the property name (what you refer to as "model") as a string parameter.
Then you can access it using the object[key] syntax.
$scope.checkBoxValueChanged = function(propName) {
if($scope[propName] === 'AA') {
$scope[propName] = 'BB';
} else {
$scope[propName] = 'AA';
}
};
BTW, in JS, scope.model is equivalent to scope['model'], so the dot syntax won't work as you want it to.

Related

Getting elements from array based on property values (AngularJS)

I have an array of players, each player is an object that has a number of properties, one is "goals".
var players = [
{
"id":"4634",
"name":"A. Turan",
"number":"0",
"age":"28",
"position":"M",
"goals":"1"
},
{
"id":"155410",
"name":"H. Çalhano?lu",
"number":"0",
"age":"21",
"position":"A",
"goals":"0"
},
{
"id":"4788",
"name":"B. Y?lmaz",
"number":"0",
"age":"30",
"position":"A",
"goals":"2",
}
]
I've written a function to cycle through the array and push every element that has more than '0' goals to an array, topScorers. Like so:
$scope.topScorerSearch = function() {
var topScorers = [];
$scope.teamDetails.squad.forEach(function(o) {
if (o.goals > 0) {
topScorers.push(o)
}
});
return topScorers;
}
With the function called as {{topScorerSearch()}}.
This returns only players who have scored. Perfect.
However, I want to run this on other properties, which will result in a lot of repetitious code. How can I make this a general purpose function that can be executed on different properties?
I tried including the 'prop' parameter, but it didn't work:
$scope.topScorerSearch = function(prop) {
var topScorers = [];
$scope.teamDetails.squad.forEach(function(o) {
if (o.prop > 0) {
topScorers.push(o)
}
});
return topScorers;
}
...and called the function like this:
{{topScorerSearch(goals)}}
Why doesn't this work? Where am I going wrong?
I believe the issue is that prop will not resolve to goals because goals is being treated as a variable with a null or undefined value, making prop null or undefined.
If you use the alternative way of accessing object properties object["property"] and use the function {{topScorers("goals")}} it should work out.

Angularjs: Watch object and compare to original object

I have a vm with two objects in it:
vm.obj = {
intObj1: {
title: 'title1'
},
intObj2: {
name: 'name1'
}
}
The vm.obj is bound to the view (I am using the controller as syntax)
I want to have the original data so I cloned the model using lodash:
var originalModelState = _.cloneDeep(vm.obj);
I am watching for changes in the model compared to the original state:
$scope.$watch('vm.obj', function(newValue, oldValue){
if (newValue !== originalModelState){
}
}, true);
Sadly newValue !== originalModelState is always different, which is expected as the references are different. I tried also comparing newValue with oldValue but the issue there is that if the user changes a property for example: vm.obj.intObj1.title = 'new title' and then change back to the original value `vm.obj.intObj1.title = 'title1' I cannot detect that the vm is the same as the original value. How can I do this ?
Have you considered
var originalModelState = JSON.stringify(vm.obj);
...
if (JSON.stringify(newValue) != originalModelState){
}
Comparing objects as strings is imho a very effective and easy way to spot differences, especially when you not know what to look for.
Not sure, if I understood correctly what you wanted to ask. The watcher callback is only executed, if something in your object has changed. The 'true' performs a deep watch.
If you only want to know, if the value deep in your object is equal to the originial value on the same position, you could check in the watcher:
$scope.$watch('vm.obj', function(newValue){
if (originalModelState.intObj1.title === newValue.intObj1.title) {
// do something
}
}, true);

$.grep to return property after match

I couldn't find any instances where this was being done so I'm asking you brainy people out there if there's a nice easy way to do what I'm wanting.
Trying to map two arrays together. One array has a list of the IDs (Foos), and the other array has all the properties (bars) for those IDs. Want to keep everything in my angular controller.
Here's a snippet. I'm trying to match on ID and map into the Name property.
$scope.Foos = $.map($scope.Foos, function (foo) {
return {
ID: foo.ID,
Name: $.grep($scope.bars, function(b){
return b.ID === foo.ID;
}).Name,
Property: $.grep($scope.bars, function(b){
return b.ID === foo.ID;
}).Property
};
});
What I understand is that $.grep will return the object based on the criteria, can I then call properties of that returned object?
Update:
Foos is ID (guid)
Bars is ID(guid), Name & Property
$.grep returns an array, not an object, so to do what you are wanting you would need to do something like:
Name: $.grep($scope.bars, function(b){
return b.ID === foo.ID;
})[0].Name
The problem here however is if there is no match , $.grep will return an empty array and you will end up throwing an error trying to get the first element from that empty array.
You really should look the properties up first, not while trying to build a more complex object
Something like:
$scope.Foos = $.map($scope.Foos, function (foo) {
// first filter the array
var bars = $.grep($scope.bars, function (b) {
return b.ID === foo.ID;
});
// now test we have result, if not make it ... empty string???
var name = bars.length ? bars[0].Name : '';
// do similar for `Property`
return {
ID: foo.ID,
Name: name,
......
};
});
This could also be modified to have some utility functions like getNameFromBars() and put the $.grep in there and return value found or the default.
If you wanted to get rid of jQuery you could use Array.prototype.map() and Array.prototype.filter() to replace $.map and $.grep.
Also $filter could be used.

How does one reassign variables in an object?

For a class I'm taking, I need to reassign an object's properties to "Unknown". Here is the sample problem:
//In the function below, "person" will be passed in as an object that represents a person with properties such as name, age, gender, etc.
//Loop through all the properties of the object and set each value equal to "Unknown"
//For example, if "person" is {name: "Dolph L.", age: 33} then the function would return {name: "Unknown", age: "Unknown"}
function describePerson(person) {
//code here
}
If I'm understanding is correctly, it says that I must loop through the object and reassign it's properties to "Unknown". What I've been trying to do is this:
function describePerson(person) {
for (var prop in person) {
if (prop) {
return "Unknown";
}
}
}
I'm very new to Javascript and could really use some help here.
Thanks
for (var prop in person) {
if (person.hasOwnProperty(prop)) {
person[prop] = "Unknown";
}
}
return person;
You don't want to return in the loop, you want to modify each property of the object using the = operator.
The reason behind hasOwnProperty is the following.
person is an object. The object inherits properties from its Prototype. You don't care about those inherited properties, so you call hasOwnProperty which returns true if the property is one you gave it.

Proper way to sort a backbone.js collection on the fly

I can successfully do this:
App.SomeCollection = Backbone.Collection.extend({
comparator: function( collection ){
return( collection.get( 'lastName' ) );
}
});
Which is nice if I want to have a collection that is only sorted by 'lastName'. But I need to have this sorting done dynamically. Sometimes, I'll need to sort by, say, 'firstName' instead.
My utter failures include:
I tried passing an extra variable specifying the variable to sort() on. That did not work. I also tried sortBy(), which did not work either. I tried passing my own function to sort(), but this did not work either. Passing a user-defined function to sortBy() only to have the result not have an each method, defeating the point of having a newly sorted backbone collection.
Can someone provide a practical example of sorting by a variable that is not hard coded into the comparator function? Or any hack you have that works? If not, a working sortBy() call?
Interesting question. I would try a variant on the strategy pattern here. You could create a hash of sorting functions, then set comparator based on the selected member of the hash:
App.SomeCollection = Backbone.Collection.extend({
comparator: strategies[selectedStrategy],
strategies: {
firstName: function () { /* first name sorting implementation here */ },
lastName: function () { /* last name sorting implementation here */ },
},
selectedStrategy: "firstName"
});
Then you could change your sorting strategy on the fly by updating the value of the selectedStrategy property.
EDIT: I realized after I went to bed :) that this wouldn't quite work as I wrote it above, because we're passing an object literal to Collection.extend. The comparator property will be evaluated once, when the object is created, so it won't change on the fly unless forced to do so. There is probably a cleaner way to do this, but this demonstrates switching the comparator functions on the fly:
var SomeCollection = Backbone.Collection.extend({
comparator: function (property) {
return selectedStrategy.apply(myModel.get(property));
},
strategies: {
firstName: function (person) { return person.get("firstName"); },
lastName: function (person) { return person.get("lastName"); },
},
changeSort: function (sortProperty) {
this.comparator = this.strategies[sortProperty];
},
initialize: function () {
this.changeSort("lastName");
console.log(this.comparator);
this.changeSort("firstName");
console.log(this.comparator);
}
});
var myCollection = new SomeCollection;
Here's a jsFiddle that demonstrates this.
The root of all of your problems, I think, is that properties on JavaScript object literals are evaluated immediately when the object is created, so you have to overwrite the property if you want to change it. If you try to write some kind of switching into the property itself it'll get set to an initial value and stay there.
Here's a good blog post that discusses this in a slightly different context.
Change to comparator function by assigning a new function to it and call sort.
// Following example above do in the view:
// Assign new comparator
this.collection.comparator = function( model ) {
return model.get( 'lastname' );
}
// Resort collection
this.collection.sort();
// Sort differently
this.collection.comparator = function( model ) {
return model.get( 'age' );
}
this.collection.sort();
So, this was my solution that actually worked.
App.Collection = Backbone.Collection.extend({
model:App.Model,
initialize: function(){
this.sortVar = 'firstName';
},
comparator: function( collection ){
var that = this;
return( collection.get( that.sortVar ) );
}
});
Then in the view, I have to M-I-C-K-E-Y M-O-U-S-E it like this:
this.collections.sortVar = 'lastVar'
this.collections.sort( this.comparator ).each( function(){
// All the stuff I want to do with the sorted collection...
});
Since Josh Earl was the only one to even attempt a solution and he did lead me in the right direction, I accept his answer. Thanks Josh :)
This is an old question but I recently had a similar need (sort a collection based on criteria to be supplied by a user click event) and thought I'd share my solution for others tackling this issue. Requires no hardcoded model.get('attribute').
I basically used Dave Newton's approach to extending native JavaScript arrays, and tailored it to Backbone:
MyCollection = Backbone.Collection.extend({
// Custom sorting function.
sortCollection : function(criteria) {
// Set your comparator function, pass the criteria.
this.comparator = this.criteriaComparator(criteria);
this.sort();
},
criteriaComparator : function(criteria, overloadParam) {
return function(a, b) {
var aSortVal = a.get(criteria);
var bSortVal = b.get(criteria);
// Whatever your sorting criteria.
if (aSortVal < bSortVal) {
return -1;
}
if (aSortVal > bSortVal) {
return 1;
}
else {
return 0;
}
};
}
});
Note the "overloadParam". Per the documentation, Backbone uses Underscore's "sortBy" if your comparator function has a single param, and a native JS-style sort if it has two params. We need the latter, hence the "overloadParam".
Looking at the source code, it seems there's a simple way to do it, setting comparator to string instead of function. This works, given Backbone.Collection mycollection:
mycollection.comparator = key;
mycollection.sort();
This is what I ended up doing for the app I'm currently working on. In my collection I have:
comparator: function(model) {
var methodName = applicationStateModel.get("comparatorMethod"),
method = this[methodName];
if (typeof(method === "function")) {
return method.call(null, model);
}
}
Now I can add few different methods to my collection: fooSort(), barSort(), and bazSort().
I want fooSort to be the default so I set that in my state model like so:
var ApplicationState = Backbone.Model.extend({
defaults: {
comparatorMethod: "fooSort"
}
});
Now all I have to do is write a function in my view that updates the value of "comparatorMethod" depending upon what the user clicks. I set the collection to listen to those changes and do sort(), and I set the view to listen for sort events and do render().
BAZINGA!!!!

Resources