Pass a variable by reference from Angular2 template - javascript

Let's say I have a variable called isVisible. And I have a method called
ReverseVariable(variable: boolean)
{
variable = !variable;
}
I want to call this method from a template like
<button (click)="ReverseVariable(isVisible)"></button>
I want to give it isVisible in the parameters and have isVisible reverse itself. Something like the following example is not an option
ReverseVisibility()
{
this.isVisible = !this.isVisible;
}
Is there any way that I can pass the variable by reference?

Not with a primitive data type like a boolean. What you could do is make a non-primitive like an object
isVisible = {
flag: true
}
Then toggle that in your function
ReverseVisibility(isVisible)
{
isVisible.flag = !isVisible.flag;
}
Here is plnkr demonstrating this (https://plnkr.co/edit/VYEimNoHZvGxeE4S2W4L?p=preview)

Related

Binding a Vue property to an asynchronous value

I have a Vue block that I need to bind to a boolean property:
<div class="row" v-if.sync="isThisAllowed">
To calculate that property I need to make an API call using Axios, which has to be asynchronous. I've written the necessary code to get the value:
public async checkAllowed(): Promise<boolean> {
var allowed = false;
await Axios.get(`/api/isItAllowed`).then((result) => {
var myObjects = <MyObject[]>result.data.results;
myObjects.forEach(function (object) {
if (object.isAllowed == true) {
hasValuedGia = true;
}
})
});
return allowed;
}
What I did then - I'm not very experienced with Vue - is to add a property to the Vue model and assign a value to it in created:
public isThisAllowed: boolean = false;
async created() {
this.checkAllowed().then(result => {
this.isThisAllowed = result;
});
}
This works in the sense that the value I'm expecting is assigned to the property. But Vue doesn't like it and complains
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value.
Most of the values on the model are exposed via getters:
get isSomethingElseAllowed(): boolean {
return this.productCode === ProductTypes.AcmeWidgets;
}
But I need to "await" the value of the async function, which would mean making the getter async which then, of course, makes it a Promise and I can't bind that to my model?
What's the right way to go about this?
You can't define a property that way, instead define isThisAllowed in the data object
as
data: function(){
return {
isThisAllowed: false
}
}
And make checkAllowed into a normal function and set this.isThisAllowed = allowed inside it

Passing data property as function argument in vue.js

Instead of having few methods that look like:
showDiv1(){
this.showDiv1 = true
},
showDiv2(){
this.showDiv2 = true
}
I am trying to create one like:
showElements(...elementNames){
elementNames.forEach(name => {
this.$data.name = true
})
}
The idea was to pass one or few properties from data and when calling the method those elements would should up on screen.
In data I have something like this:
data() {
return {
div1 = false,
div2 = false
}
}
In html I tried to call the function on click in a couple of ways:
<button #click="showElements('div1')">Show<button>
<button #click="showElements(div1)">Show<button>
<div v-if="div1">
<p>Hello</p>
</div>
But nothing happens.
Seems like you have a syntax error. Instead of writing to your data object like this:
data() {
return {
div1 = false,
div2 = false
}
}
You should write it like this:
data() {
return {
div1: false,
div2: false
}
}
Make sure to only use syntax that fits an object in the data object. Then, you can call it like this:
<button #click="showElements(div1)">Show<button>
One more thing, when accessing the data you don't actually need to write $data. Simply write 'this.name' in order to access your data.
Dynamic property names are supposed to be accessed with bracket notation:
showElements(...elementNames){
elementNames.forEach(name => {
this[name] = true
})
}
The method is supposed to be used like:
<button #click="showElements('div1')">Show<button>

Use constant for Ember computed property dependent key

For an Ember app, is it possible to use a constant as part of a computed property key ?
So, essentially, I have a constant as below;
MY_SECTION {
MY_FIELD: "my-field-id"
}
What I want is a computed property on "my-field-id" i.e.
myCP: function() {
console.log('Inside CP...');
}.property('section.field.my-field-id.value')
However, I want to be able to use constant for my-field-id instead of using it directly. Is that possible ?
Ola #testndtv, thanks for your question! Yes it is entirely possible to use a constant in the key for a computed property, but to make use of it you will need to use the more modern syntax that #jelhan was mentioning because .poperty() is deprecated.
Here is a working example of a controller that I have tested locally and is working as you would expect:
import Controller from '#ember/controller';
import { defineProperty, computed } from '#ember/object';
const PROPERTY_ID = 'some-random-string-that-is-too-long-to-write';
export default Controller.extend({
// this is just for the example so we can show the value in the template
// it is not needed to get this to work
PROPERTY_ID: PROPERTY_ID,
init() {
this._super(...arguments);
defineProperty(this, 'myCP', computed(PROPERTY_ID, function() {
return this.get(PROPERTY_ID);
}));
},
actions: {
addOne() {
// this is just for the example to stop the result always being NaN because
// null + 1 = NaN
let value = this.get(PROPERTY_ID) || 0;
this.set(PROPERTY_ID, value + 1);
}
}
});
As you can see we are making use of defineProperty which is being imported from '#ember/object'. You can read more about it in the API documentation
The key insight here is that you need to define the property dynamically in the init() for this Ember object.
The corresponding template for this Controller is as follows:
Property ID is: {{PROPERTY_ID}}
<br>
And the value is: {{get this PROPERTY_ID}}
<br>
<button {{action 'addOne'}}>Add One</button>

Vue.js - How to pass parameters to a JavaScript filter function within a computed property?

I want to pass a variable as a parameter to a computed property.
computed: {
dishes() {
let param = this.cuisine;
let dishes = this.restaurant.restaurant_items.filter(element => {
element.param
});
return dishes;
}
},
data(){
return{
cuisine:""
}
}
Here as the param I pass a value which is an element of restaurant_items array's objects.
eg(:- is_thai)
But this doesn't output me anything. What's wrong with my code?
Computed properties don't accept parameters. But you can use a method to accomplish the same thing
methods: {
dishes(param) {
// return whatever
}
}
If I understand you correctly what you actually want to do is:
computed: {
dishes() {
return this.restaurant.restaurant_items.filter((e) => e[this.cuisine])
}
}
You need to use bracket notation to access object properties via a variable, not dot notation.

AngularJS: how to change scope in one controller with trigger in the other controller

I have two Controllers and one shared Service.
First Controller renders some text. Other Controller has a button that had to change the First Controllers scope and rerender text (with new value)
HTML
<div ng-controller="Controller1">
Value is: {{object}}
</div>
<div ng-controller="Controller2">
<button ng-click="changeValue()">Click to change Value</button>
</div>
JS
function Controller1($scope, mainServices) {
$scope.object = mainServices.getValue();
};
function Controller2($scope, mainServices) {
$scope.changeValue = function(){
mainServices.getValue('Hello');
console.log('button is pressed');
};
};
testApp.factory('mainServices', function(){
return {
getValue: function(update) {
var defaultValue = 'Hi';
if( typeof(update)==='undefined') { value = defaultValue; }
else { value = update; }
console.log('should be changed to', update);
return value;
}
}
});
On Plunker http://plnkr.co/edit/IWBEvAfvLbzJ0UD2IqGB?p=preview
Why doesn't this work? How to tell Angular to watch for changes?
The code
Well, I think this is not the best solution, but it is possible for your problem.
Instead of just changing the value itself, you have to create an object before the return statement in the factory.
var obj = {}
And then you just change a property of this object:
if( typeof(update)==='undefined') { obj.val = defaultValue; }
else { obj.val = update; }
And return the object:
return obj;
The other controller can be left unaffected, however you have to change your html:
You have to put in
{{object.val}}
in order to listen to changes.
http://plnkr.co/edit/rjsrkbaQ8QyWGGFI9HYl?p=preview
Why does this work?
It is quite simple: In javascript, if you call a function with a primitive return value like a string (yes, strings CAN be primitives in javascript), it is just a copy of this primitive, so with
$scope.object = mainServices.getValue();
you just pass a value to $scope.object, which is not affected by other calls of getValue()
But if we return an object from getValue(), we get a reference to this object. So if we make changes to this referenced object in getValue(), angularjs will be able to notice the changed object because it is tracked in both controllers.
Therefore we have to reference the same object again and again, but since javascript supports closures, this is pretty easy.

Categories