Onclick with Vue.JS - javascript

I have this two buttons:
<button onclick="filterSelection('Action')">Action</button>
and
<button onclick="filterSelection('Adventure')">Adventure</button>
Now, I want to do the same but with Vue.JS, so I created this array on my app.js
genres: [{name: 'Action'}, {name:'Adventure'}]
And in my HTML file:
<button v-for="genre of genres">{{genre.name}}</button>
That's works fine, but I don't know how to add the propertie with Vue.JS:
onclick="filterSelection('genre')"
Can you help me?

You can do this by having the attribute v-on:click="filterSelection(genre)" on your button.
Edit: Forgot quotes.

Since vue uses a virtual dom, you cannot use the "native html" events.
Instead you define click events via an event handler [docs]
<div id="example-1">
<button v-on:click="counter += 1">
Add 1
</button>
<p>
The button above has been clicked {{ counter }} times.
</p>
</div>
alternatively you can use the shorthand for v-on and use the # symbol like #click=

Related

Vue 2 not updating specific component properties despite v-if v-else directive, while the rest is updated successfully

Vue2 is not updating one specific component (<Button>) inside v-if and v-else, while the rest of the content is updated.
I have just found out a way to make this code work, but I do not catch the behaviour of Vue2 re-rendering, and I am afraid that I will not be able to make it work this way anytime, because here I only have 2 conditionally excludent blocks (or <v-if> and v-else, and now I use <span> and <div> for each).
This was the original code that does not work. The problem is that it did not update the component once the condition ('root.authentication') is changed, but seamlessly, the <p> tag is updated successfully (why <Button> not?):
<template>
<span v-if="root.authentication" data-id-logout-box>
<p>Logout</p>
<Button :root="root" text-label-preset="Salir" :on-click-preset="root.logout" />
</span>
<span v-else data-id-login-box>
<p>Login</p>
<Button :root="root" text-label-preset="Entrar" :on-click-preset="root.login" />
</span>
</template>
This second code does the trick. The only difference is that, in the previous, there were 2 span tags, while in this one, there is 1 span and 1 div tag:
<template>
<span v-if="root.authentication" data-id-logout-box>
<Button :root="root" text-label-preset="Salir" :on-click-preset="root.logout" />
</span>
<div v-else data-id-login-box>
<Button :root="root" text-label-preset="Entrar" :on-click-preset="root.login" />
</div>
</template>
I have tried to do it changing the class attribute applied to that elements, and also playing with data-* attributes, as you can see in the example. But none of them worked.
My quesiton is, as I do not have infinite tags to make it work, how could I do the workaround for this, in order to make it work with infinite nested <v-else-if>?
Thank you.
If and else elements are identical that's causing this issue. when you are changing else part to div fixes because how vue update and render template.
for more details
https://snipcart.com/blog/vue-render-functions
you can give first span and second span unique keys and that should solve the problem.

How to access a property or a method of alpine.js parent component from a child component?

This is kind of an example scenario what the problem looks like,
<div x-data="{ count : 0 }">
<div x-data>
<span x-text="count"></span>
<button x-on:click="count++">Increment</button>
<button x-on:click="count--">Decrement</button>
</div>
</div>
It would be able to increase/decrease the data count from the child component.
I thought of handling it through dispatching custom events using $dispatch() but then again in terms of design, I might need to write listeners on both parent and child component which make the logic more complex since it should be reactive as well.
There was a Github issue, and none of the proposed solutions was working.
I thought of handling it through dispatching custom events using $dispatch() but then again in terms of design, I might need to write listeners on both parent and child component which make the logic more complex since it should be reactive as well.
This is the crux of the issue, in order to do parent-child and child-parent communication you'll need to use events. In the case of child -> parent, you'll trigger increment and decrement events (which will be listened to in the parent component using x-on:increment and x-on:decrement). In the case of parent -> child, you'll need to use $watch to trigger updates whenever count updates (I'll used the new-count event name), this will be listened to on the window from the child component using x-on:new-count.window.
Here's the full working solution (see it as a CodePen):
<div
x-data="{ count : 0 }"
x-init="$watch('count', val => $dispatch('new-count', val))"
x-on:increment="count++"
x-on:decrement="count--"
>
<div>In root component: <span x-text="count"></span></div>
<div
x-data="{ count: 0 }"
x-on:new-count.window="count = $event.detail"
>
<div>In nested component <span x-text="count"></span></div>
<button x-on:click="$dispatch('increment')">Increment</button>
<button x-on:click="$dispatch('decrement')">Decrement</button>
</div>
</div>
In the case you've presented, the count state might be better served by using a global store that integrates with Alpine.js such as Spruce, in which case we'll read and update a shared global store to which both the parent and child components are subscribed (see the Spruce docs). You can find the working example in the following CodePen.
<div x-data x-subscribe="count">
<div>In root component: <span x-text="$store.count"></span></div>
<div x-data x-subscribe="count">
<div>In nested component <span x-text="$store.count"></span></div>
<button x-on:click="$store.count ++">Increment</button>
<button x-on:click="$store.count--">Decrement</button>
</div>
</div>
<script>
Spruce.store('count', 0);
</script>
The final solution that should be mentioned is that removing the nested component would mean that the count increment and decrement would work as expected. Obviously this example was probably simplified & meant to be illustrative, so this solution might not work in a lot of cases. Note: the only difference is removing the second x-data.
<div x-data="{ count : 0 }">
<div>
<span x-text="count"></span>
<button x-on:click="count++">Increment</button>
<button x-on:click="count--">Decrement</button>
</div>
</div>
Another way is to use the magic $store 👉as a Global State:
<div x-data x-init={Alpine.store('count', 0)}>
<div x-data>
<span x-text="$store.count"></span>
<button x-on:click="$store.count++">Increment</button>
<button x-on:click="$store.count--">Decrement</button>
</div>
</div>

Angular ng-class not working but regular class attribute works

I have this view template that is a child to another view.
The parent view of this view is a child to the index.html where I am importing my angular and ui-router javascript.
i.e index.html > other view > view below
When I try to change the class = "bubble me" below - which works fine ,to ng-class = "bubble me" my css is not loaded. Am I missing something? The issue is isolated to this view only.
<div class="top"><span>To: <span class="name">{{chat.name}}</span></span></div>
<div class="chat">
<div class="conversation-wrapper">
<div class="conversation-start">
<span>Today, 6:48 AM</span>
</div>
<div class="bubble me" ng-repeat = "message in sent_received">
{{message.msg}}
</div>
<div class="write">
<input ng-model = "input.message" type="text" />
<a ng-click= "sendMsg()" class="write-link send"></a>
</div>
does ng-class work only for conditional classes? I would like to
combine my regular hard coded classes with the conditional ones so I
dont have both a class attribute and an ng-class attribute in my
tags..is there no way of doing this? - in the code above the bubble is
not dynamic. I would like to make the me class only dynamic
This might work for your case.
ng-class="value=='true'?'bubble me':'bubble'"

Listen to events outside of template, but only when the template is present

I use IronRouter to structure my app into controllers (routers), on which I started attaching my events. So far so good.
I then started using the {{#contentFor ...}} feature and since then, my events don't fire anymore, because the region I render the relevant element, is part of a different DOM tree.
Is there any approach to still listen to these events? I considered simply adding a global listener, but that would remove a lot of flexibility from the events.
CoffeeScript:
MyRouter = RouteController.extend(...)
MyRouter.events(
'click .inside': (event) ->
alert("inside") # works
'click .outside': (event) ->
alert("outside") # does not work
)
HTML:
<button type="button" class="inside">
inside
</button>
{{#contentFor 'anotherDomRegion'}}
<button type="button" class="outside">
outside
</button>
{{/contentFor}}
And layout file:
<h1>event demo</h1>
<div>
{{> yield}}
</div>
<div>
{{> yield 'anotherDomRegion'}}
</div>
I've run into the same problem myself. The only way I've been able to work around it is to set the contentFor to a template so you can assign your events to that template.
{{> contentFor region="anotherDomRegion" template="anotherDomRegion"}}
then;
<template name="anotherDomRegion"> ... </template>
and;
Template.anotherDomRegion.events({ ... });
Good luck!

How can I use the id of an element to trigger an event in Meteor.js

I am currently using Meteor 0.6.3
The following scenario, using the 'id' as selector, doesn't work:
Template:
<template name="menu">
<div>
<button id="showmap" class="btn-primary">Show map</button>
</div>
</template>
JS:
Template.menu.events({
'click #showmap' : function () {
alert("test");
}
});
If I use a 'class' instead of the 'id' everything works fine:
Template:
<template name="menu">
<div>
<button class="btn-primary showmap">Show map</button>
</div>
</template>
JS:
Template.menu.events({
'click .showmap' : function () {
alert("test");
}
});
I have seen several examples of people using 'id' as selector. So what could I be doing wrong?
I tried your code and it doesn't work like you said. Strange thing is the event for the class selector doesn't work either. However, I have lots of packages added on, so I wouldn't be surprised if one of them is interfering.
I found this response on SO to a very similar question:
Setting simple events in meteor
So you might want to search through the bug reports and post it if it isn't already posted.
https://github.com/meteor/meteor/issues
The best workaround is probably to use class as the selector and then test against event.currentTarget.id which should have the id of the element clicked.
I use attributes. ID doesn't seem to work for me too. For example:
<button data-do-something>
Click Me
</button>
'click [data-do-something]': function(eventArgs, template){
}
Good thing about attributes is that you can also assign values to the attributes, and use them with the events. for example:
<button data-do-something="hello">
Click Me
</button>
'click [data-do-something]': function(eventArgs, template){
var data = eventArgs.target.getAttribute('data-do-something');
if(data === 'hello') console.log('found hello!");
}

Categories

Resources