Ember.js computed property not firing - javascript

I have a computed property thats not firing when a checkbox is checked. I just need to switch a property's value from 1 to 0 if its checked.
App.Address = Ember.Object.extend({
shipType: 1,
shipType: function() {
var type = this.get('shipType');
if (type === 1) {
type = 0;
return type;
} else {
type = 1;
return type;
};
}.property('shipCommerical')
})
And in my template:
<label>{{view Ember.Checkbox checkedBinding='shipCommerical'}} Check Me </label>
I have other computed properties located in the same place and in the same way. The only difference is they are text fields and not checkboxes. Does that make a difference?

Well, you've got ship commercial spelled incorrectly, but it appears you have it spelled incorrectly in both places. Additionally you have a recursive loop where your computed property needs itself, I'm going to assume you meant to use shipCommercial instead of shipType inside the computed property.
Template
<label>{{input type='checkbox' checked=shipCommercial}} Check Me </label>
Properties
shipCommercial:true,
shipType: function() {
var shipCommercial = this.get('shipCommercial');
return shipCommercial ? 0 : 1;
}.property('shipCommercial')
Example
http://emberjs.jsbin.com/zimopise/1/edit

Related

Angular generic function handler not update component properties

I have a component that has 2 checkboxes that in each change event - aside text is changed.
I want to avoid double code so I created a function that receive two arguments the chackbox model and text to change but it seems that the value are passed by value.
Is it possible to pass it by reference? if not - what it the best-practice solution?
<input type="checkbox" id="aa" [(ngModel)]="checkboxOne" (change)="genericOnChange(checkboxOne,textOne)">
{{textOne}}
<input type="checkbox" id="nn" [(ngModel)]="checkboxTwo" (change)="genericOnChange(checkboxTwo,textTwo)">
{{textTwo}}
export class AboutComponent implements OnInit {
constructor() { }
checkboxOne = false;
checkboxTwo = false;
textOne = '';
textTwo = '';
ngOnInit() {}
genericOnChange(checkboxModel,componentProperty){
if(checkboxModel){
componentProperty ="pew pew pew!"
}
else{
componentProperty ="laser gun off!"
}
}
}
Please see stackbliz (about.component)
It’s passing the value because there isn’t a reference, it’s a primitive (you don't have a pointer like you would in C). You could create an object, or you could pass the variable name in as a string and do:
this[myVariable]. I would recommend the former (an object), as you could have a checkbox object with both checkboxes as properties:
checkboxes = {one: true, two: false}
You could create a wrapper object around your checkboxProperties, and pass that reference as a single parameter to your genericOnChange(...) function
genericOnChange(chk:CheckboxProperties){
if(chk.checked){
chk.name ="pew pew pew!"
}
else{
chk.name ="laser gun off!"
}
}
Now you are modifying a property of the object, and not a primitive string. Your changes will be reflected on the template as you are expecting.
Full example below:
https://stackblitz.com/edit/angular-basic-tutorial-r7eaup?file=app%2Fabout%2Fabout.component.ts

Vue-Form-Generator schema is not reactive to computed properties

I have computed property in my data this.coinPairingOptions that needs to render its radio buttons based on some of the other fields in this schema. I have reduced the amount of code in the file to save space.
data: function () {
return {
schema: {
{model: "symbolPair", type: "radios", label: "Pair with", values:
this.coinPairingOptions, required: true}
},
computed: {
coinPairingOptions() {
console.log("computing coinPairingOptions")
let coin = this.model.symbol.toUpperCase();
let options = [];
if (this.model.exchange === 'Coinbase') {
options = this.getCoinbasePairs
} else if (this.model.exchange === 'Binance') {
options = this.getBinancePairs
} else {
}
console.log(options.get(coin));
return options.get(coin);
},
}
In the dev tools I can see the computed property changing to the correct values however it is not changing in the data. Apparently, this is appropriate behavior, but what is a way around this? I have tried putting {{this.coinPairingOptions}} in the html and it errors because it's a computed property with not value initially.
Any help would be appreciated!
You can't use computed property in data, because data evaluates before the computed properties did.
You can use a watcher to achieve the intended result. Have a look at the documentation, you can add the argument immediate to trigger the callback immediately with the current value of the expression.
Computed properties are already accessible in the template by using {{}}. You don't need to put a this in front of the computed.

angularjs function failing because of extra $$hashKey

I have the below HTML:
<li ng-click="toggleBeep(beep)" ng-class-odd="'gradient-two'"
ng-class-even="'gradient-three'" ng-repeat="beep in beeps">
<span>{{beep.name}}</span>
<label class="bold" ng-show="isSelected(beep)">selected</label>
</li>
JavaScript (AngularJS):
$scope.beeps = $sounds.getAll();
// get stored beep from localStorage
var notification_beep =
angular.fromJson(localStorage.getItem('notification_beep'));
console.log($scope.beeps[0]);
console.log(notification_beep);
// handle change sound on click event
$scope.toggleBeep = function (beep) {
$cbSounds.play(beep.file);
$scope.selected = beep;
localStorage.setItem('notification_beep', angular.toJson(beep));
};
$scope.isSelected = function (beep) {
return $scope.selected === beep;
};
Now, when I click on any li I get the selected label is shown because of the $scope.isSelected function. However, when I try to add this line $scope.selected = notification_beep which is the beep object stored in the localStorage the label is not shown and I get the below return values.
The only difference I could spot is that $$hashkey is present on $scope.beeps[0] while it's not on notification_beep. Could this be the cause? Thanks.
The following comparison:
$scope.selected === beep
Will only return true if the two variables reference the same object.
The following line will create a new object:
var notification_beep = angular.fromJson(localStorage.getItem('notification_beep'));
So it will not reference the same object as $scope.selected.
To clarify, this will return false: { name: 'Beep 1' } === { name: 'Beep 1' }
The simplest solution is to instead compare against a unique primtive of the objects.
For example:
return $scope.selected.name === beep.name;
The $$hashkey property is inserted into the object by ng-repeat and is used to track which object corresponds to which DOM template. The reason it doesn't exist in notification_beep is because angular.toJson removes the property from the object.

Angular filter with minimum and maximum values

I'm having some trouble getting angular to properly filter my results. I'm attempting to use a custom filter that gets arguments from a minimum input and a maximum input.
/index.html
<input ng-model="minHorsepower">
<input ng-model="maxHorsepower">
...
tr(ng-repeat="plane in planes | filter:horsepowerFilter")
/controllers.js
//Horsepower filter
$scope.horsepowerFilter = function(plane) {
var ret = true;
if($scope.minHorsepower && $scope.minHorsepower > plane.horsepower) {
ret = false;
}
if($scope.maxHorsepower && $scope.maxHorsepower < plane.horsepower) {
ret = false;
}
return ret;
};
$scope.planes = [
{
'make' : 'Piper',
'model' : 'Arrow',
'modelNumber' : 'PA-28R-180',
'horsepower' : '180',
'gear' : 'retractable',
},
{
'make' : 'Piper',
'model' : 'Arrow',
'modelNumber' : 'PA-28R-200',
'horsepower' : '200',
'gear' : 'retractable',
}
];
It works INITIALLY when I set $scope.minHorsepower/$scope.maxHorsepower in controllers.js, but only initially, not when I put something else in the <input>s. Furthermore, it prefills the inputs AND filters the results. It just doesn't work properly when I change the value of the inputs.
I've referenced this Stack Overflow thread, but I can't find any material differences in our code... AngularJS multiple filter with custom filter function
Thanks for the help.
To ensure the model values are numbers and not strings, change the type for your inputs to be number.
<input type="number" ng-model="minHorsepower" />
<input type="number" ng-model="maxHorsepower" />
Also, make sure your model values are numbers and not strings.
Alternatively, you can run everything through parseFloat(...) in your filter.
Unfortunately, I can't pinpoint exactly the problem you're having with your code. However, I think I have created a plnkr that (I believe) works as intended.
Apart from parsing the inputs with parseFloat, the logic seems to be the same. Not parsing the inputs to a numeric form shouldn't "break" it, but will possibly make it behave strangely ("9" > "10" for example).
Anyway, hopefully you can pull out the useful pieces and get it working.
Since you only send to the filter a function, it doesn't know to watch for any value changes, and thus to trigger the filter function when it happens.
When you define a filter as {{ filter_expression | filter : filterValue}}, angular watches the filterValue and triggers the filter function when it changes.
To achieve what you need you can define your own filter:
angular.module('myApp')
.filter('range', function(){
return function(items, property, min, max) {
return items.filter(function(item){
return item[property] >= min && item[property] <= max;
});
};
});
and call it like this:
ng-repeat="plane in planes | range : 'horsepower' : minHorsepower : maxHorsepower"

return an obj of checkbox values

I'm trying to get an object of checkbox names and values. Suppose I have this form:
<form>
<input type="checkbox" name="email" />
<input type="checkbox" name="name" />
<input type="checkbox" name="hi" />
And Assuming that the first and third are checked, I want this obj:
{ email: 1, name: 0, hi: 1 }
Here's what I tried:
$(':checkbox').map(function() { return this.name + '=' + (this.checked ? 1 : 0) } }).get();
And that gives me:
['email=1', 'name=0', 'hi=1']
But I don't know what do to from here.
Am I going about this wrong?
According to the .map() method doco, .map() returns "a jQuery-wrapped array". Given that you want an object you can instead do something like this:
var checkboxes = {};
$(':checkbox').each(function() {
checkboxes[this.name] = this.checked ? 1 : 0;
});
Noting that if you have checkboxes with the same name (which is valid as far as html forms go) then your object will only keep the value of the last checkbox for each name.
Yeah, you're going about this pretty wrong. From your use of '=' it looks like you expect the function to return JavaScript code that is then run using eval. That's not the way JavaScript operates. Since you're concatenating this.name with a string and a number, JavaScript does its implicit type coercion and returns a string from the function, so you get an array of strings.
The .map() function will always return an array; for miscellaneous operations that don't return an array, you should use the generic .each() iterator.
Here is a quick plugin that does what you want.
$.fn.serializeCheckboxes = function() {
var ret = {};
this.each(function(ix,elm) {
ret[elm.name] = elm.checked ? 1 : 0;
});
return ret;
}
Try this:
$('input[type="checkbox"]').each(function() {
var name = $(this).attr('name');
obj[name] = $(this).is(':checked') ? 1 : 0;
});
http://jsfiddle.net/T7fja/1/
You can try setting the properties using the associative array syntax: ob["property"] = ...
See this working fiddle: http://jsfiddle.net/tuando/JwYFz/

Categories