Access v-for current item from v-bind directive function call - vuejs2

I need to loop over some tasks objects with a v-for directive.
<div v-for="(currentTask, taskName) in step.tasks">
<span>{{ currentTask.title }}</span>
<button :class="getTaskButtonProp(currentTask, 'class')" :disabled="getTaskButtonProp(currentTask, 'disabled')">{{ getTaskButtonProp(currentTask, 'caption') }}</button>
</div>
The vue instance method involved:
// …
,methods: {
getTaskButtonProp : function (task, key) {
let out = tasksStatusDescriptor[task.status][key];
// out variable manipulation …
return out;
}
}
The data involved:
Vue complains and says ReferenceError: currentTask is not defined., as if v-bind directive parsing did not grant access to the current loop scope.
Did I miss something here ? Is there some sort of special syntax here ? Or did anyone already spot a workaround ? Thank you.
EDIT
This code is perfectly fine. A missing attribute's ending double quote boundary, up in the dom tree, led to a set of errors that have now disappeared.

Related

Pass string variable from Django to Vuejs method

I'm passing an parameter from Django to a Vue method in my html as such:
# Django view
context = {
'var1': var1,
}
<!-- html -->
<div>
<p>Display var1: {{var1}}</p>
<button #click.prevent="doThis({{var1}})">Do This</button>
</div>
<!-- html result below
Display var1: value_of_var1
-->
The above works perfectly however, the doThis({{var1}}) gives an error.
// Vue method
method: {
doThis(var1){
console.log(var1)
}
}
I get the following in the console:
undefined
...[Vue warn]: Property or method "value_of_var1" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.
What am I doing wrong?
How can I get the above error when I'm passing in a variable to the method?
My first answer above works so I'm leaving it. It is however not optimal for the purpose I wanted. Estradiaz comment is really what I needed. I was missing the quotes '' in my code. This is required when passing strings into methods. So the solution is:
<!-- html -->
<div>
<p>Display var1: {{var1}}</p>
<button #click.prevent="doThis('{{ var1 }}') ">Do This</button>
</div>
I couldn't figure out what is happening above but I found a way around it. I let var1 display in the html then added a style of display:none. I then used javascript to fetch the contents in my vuejs file:
<!-- html -->
<div>
<p id="get_var1" style="display: none;">{{var1}}</p>
<button #click.prevent="doThis()">Do This</button>
</div>
// Vue method
method: {
doThis(){
let var1 = document.getElementById("get_var1").textContent
console.log(var1)
}
}
// Console:
// Value_of_var1
Note that the only reason this is ok is that this isn't sensitive or secret information.

Access v-for model used within Vue 2 custom directive

Question
How can I update the model data used within a Vue 2 custom directive?
Setup:
<ul>
<li v-for="item in items">
<select my-directive="item">...</select>
</li>
</ul>
So let's say I have a directive with a hook like this:
Vue.directive('chosenjs', {
inserted: function (el, binding, vnode) {
// Here, I'm setting up a callback with the jQuery Chosen library, but this could be any callback.
jQuery(el).chosen().change(function(event, change) {
// CODE HERE...
});
}
});
In the CODE HERE... section, if binding.value is a pointer (array/object), then this is straight-forward. For example, for an array, I'd do e.g. binding.value.push(someValue), and Vue's observable will handle it. But if the value is a primitive, then what can be done?
If the directive is not used within a v-for loop, you can use the vnode to modify the data in the component. It works great as I show here.
But if it is in a v-for, it seems there's no way. Even with access to the binding.expression, there's no way to get at the v-for item.
Background
I'm trying to work with Vue and the ChosenJS jQuery library. I got most of the way there with this answer, but there is a bug when the directive is used within a v-for loop.

When v-for array created by computed option changs, the DOM doesn't change accordingly

Recently, I've encountered a problem that caused by the computed option of vuejs.
Firstly, I use v-for to loop for an array (soloColImgs) which is created by the computed option.
my HTML
<div class="show-box" v-for="item in soloColImgs" track-by="$index">
<img v-bind:src="item.imgUrl"/>
<a v-bind:href="item.itemUrl" target="_blank"></a>
</div>
my JS
//...
computed: {
soloColImgs :function(){
//....
},
methods: {
change:function(){
this.soloColImgs.pop();
}
}
Secondly, I change the array (soloColImgs) by using pop() or splice() etc...When I look into the console, the array can change accordingly, however, the DOM does't change at all. It would be greatful if anyone can help me out of this.
The point of a computed property is that its determined solely by the function that defines it. You cannot change it directly, you must change it by acting on the dependencies. The dependencies are the properties that are used to calculate the returned value.

closure within v-for, attribute interpolation

I have this basic setup
<div v-for="n in 4">
<some-component #on-some-event="onSomeEvent(n)"></some-component>
</div>
the on-some-event is dispatched within some-component. but I need to know which of these components sent the message. with the setup above, only n is passed into the method. and the data that the event sends is nowhere.
I'd like to interpolate the function so that the method looks like this
onSomeEvent(n){
return (obj)=>{
console.log(`component ${n} sent ${obj}`);
};
}
but wrapping onSomeEvent with {{}} throws a warning: attribute interpolation is not allowed in Vue.js directives and special attributes.
I could just pass the n index into the component but that seems less elegant because I may not have the ability to modify some-component
I am somewhat new to Vue, so perhaps I am missing some core functionality for this type of thing?
<div v-for="n in 4">
<some-component #on-some-event="onSomeEvent | pass n"></some-component>
</div>
....
filters: {
pass(handler, n) {
return function() {
handler()(n, ...arguments)
}
}
},
methods: {
onSomeEvent() {
console.log(...arguments)
}
}
https://jsfiddle.net/2s6hqcy5/2/
You didn't miss anything, the message is correct, in Vue, you won't be able to use interpolation like that.
http://vuejs.org/guide/syntax.html#Interpolations
However, you may want to change how you manage events and pass data between components. In your example, you can just bind the data like this:
<div v-for="n in 4">
<some-component :n="n"></some-component>
</div>
In your component, declare the prop:
Vue.component('some-component', {
props: ['n'],
...
Now, inside each component, you have the n available like any other property (http://vuejs.org/guide/components.html#Props).
Then when dispatching your event, you can call it like this, with no need for a param:
onSomeEvent()
On the event itself, you can access the n:
console.log('Component' + this.n + ...)
https://jsfiddle.net/crabbly/mjnjy1jt/

When does binding to ref attribute become valid in Aurelia?

This is a follow up to this question: Access a DOM element in Aurelia
Is there a hook in the Screen Activation Lifecycle which allows me to run code after ref bindings have been set up? Currently it seems like there is a period of time after the activate hook is called when the ref bindings are not set up yet and then at some point they get activated. I tested this by adding a <div ref="myDiv"></div> to near the bottom of welcome.html in a cloned version of the latest (v0.13.0) skeleton-navigation repo and testing the existence of the reference in the view-model like this:
export class Welcome{
heading = 'Welcome to the Aurelia Navigation App!';
firstName = 'John';
lastName = 'Doe';
testMyDiv() {
console.log("Getting my div")
console.log(this.myDiv)
}
get fullName(){
this.testMyDiv()
return `${this.firstName} ${this.lastName}`;
}
welcome(){
alert(`Welcome, ${this.fullName}!`);
}
}
A snippet of the bottom of the template...
<button type="submit" class="btn btn-default">Submit</button>
</form>
<div ref="myDiv"></div>
</section>
</template>
This is a snapshot of what I see in the console...
welcome.js:10 Getting my div
welcome.js:11 undefined
welcome.js:10 Getting my div
welcome.js:11 undefined
welcome.js:10 Getting my div
welcome.js:11 <div ref=​"myDiv" class=​"au-target">​</div>​
welcome.js:10 Getting my div
welcome.js:11 <div ref=​"myDiv" class=​"au-target">​</div>​
(continues)
The print outs like this goes on indefinitely. You can see that fullName() is being called regularly to update the screen if the name changes (I assume this is the dirty checking)... but you can see that at the beginning there is a period when the referenced div is NOT valid as a property of the view-model, and then it IS valid. Can someone explain this? Is there a way to hook into the view-model after the ref becomes valid?
In general, bindings are processed and available after the bind callback. However, in this case since you need to access the DOM element, you will need the ViewModel to be bound and attached to the view, so use the attached callback.
class ViewModel {
bind() {
this.refItem == undefined; // true
}
attached() {
this.refItem == undefined; // false
}
}
As you noted in the comments, more information on the activator callbacks is available here: http://aurelia.io/docs.html#extending-html