Responding to a click on a Vue element programmatically - javascript

Essentially, I want my Vue instance to respond to a click on an uploaded thumbnail.
I'm using the FineUploader Vue package with the template layout per the docs (see end of the question). Upon uploading an image, a tree like this is outputted:
<Root>
<Gallery>
<Thumbnail>
</Gallery>
</Root>
Coming from a jQuery background I really have no idea about the 'correct' way to go about this given that the Thumbnail Template is defined by the package already, and so I'm not creating my own Thumbnail template. I know that I can access elements like this:
let thumb = this.$el.querySelector('.vue-fine-uploader-thumbnail');
And perhaps a listener
thumb.addEventListener('click', function() {
alert('I got clicked');
});
But dealing with the Vue instance being re-rendered etc. I'm not familiar with.
Vue Template:
<template>
<Gallery :uploader="uploader" />
</template>
<script>
import FineUploaderTraditional from 'fine-uploader-wrappers'
import Gallery from 'vue-fineuploader/gallery'
export default {
components: {
Gallery
},
data () {
const uploader = new FineUploaderTraditional({
options: {/*snip*/}
})
return {
uploader
}
}
}
</script>

In order to respond to click events you add the v-on:click (or it's short form: #click) to whatever tag you want.
If you have elements that are nested that respond to the click event you might experience that a click on a child triggers a parents click event. To prevent this you add #click.stop instead, so that it doesn't trigger the parents click.
So you would have something along the lines of:
<Gallery #click="myFunction" />

Related

v-img load dynamic images raise eror [Vuetify] Image load failed

In my case, I have two unrelated components. The first component has a button. The second component has <v-img> element of the Vuetify framework. The version of Vuetify which I use is 2.2.4. When the user clicks the button I pass some paraments by EventBus. I want to change the image in the second component after that click. For some reason in console I see that error: [Vuetify] Image load failed. eager property don't work. I also changed v-img to img. The result is the same. The image doesn't change. How to solve this problem for your opinion?
The first component (button click event logic):
EventBus.$emit('showLegend', {
imageName: 'http://domain/logo.png',
legendVisible: true
})
The second component:
<template>
<v-img
eager
v-if="legendVisible"
:src="legendURL">
</v-img>
</template>
<script>
import { EventBus } from '../../services/events.js'
export default {
data () {
return {
legendURL: 'http://domain/logo.png',
legendVisible: true
}
},
created () {
EventBus.$on('showLegend', data => {
if (data) {
this.legendURL = data.imageName
this.legendVisible = data.legendVisible
}
})
}
}
</script>
So you are saying that the image is bound correctly and displays, but the issue is with the change in URL after the emit via EventBus happened? If it had not worked in the first place, I'd have assumed you might need something related to require. Many times for static images that's the issue. You'd have to write
<v-img src="require('http://domain/logo.png')"></v-img>
However, I could not get this syntax to work with my own dynamic variables coming from a v-for="card in cards" myself until I used
<v-img :src="require('#/assets/' + card.imgSrc + '.jpg')"></v-img>
which I find rather dissatisfying.

Vue.JS - listen to click on component

I'm fairly new to Vue.JS and currently having an issue listening to a click event on a component.
JS:
Vue.component('photo-option', {
data: function () {
return {
count: 0
}
},
props: ['src'],
template: `
<img :src=src v-on:click="$emit('my-event')" />
`
});
HTML:
<photo-option :src=uri v-for='uri in aboutUsPhotos' v-on:my-event="foo" />
...where foo is a method on my main Vue instance.
The above is based on the Vue.JS docs for handling component events, and I can't see what I'm doing wrong. The alert doesn't fire, and there's no errors in the console.
Before I found those docs, I also tried simply adding v-on:click='...' to both the JS (i.e. the template) and the HTML, each with no success.
What am I doing wrong?
[EDIT]
This is happening because the code is picked up by a lightbox script and has its DOM position changed. So presumably the binding/event attachment is being lost.
Does Vue have any way of allowing for this, perhaps by 'reinitialising' itself on an element, or something?

Creating a global modal using react-redux and foundation reveal

I'm creating a modal that displays information about a specific user and it's triggered by clicking on a picture. The modal should be able to fire up from different components. My approach is as follows (I use React with Redux):
create store with a "modal" property that's set to a reducer "modalReducer"
modal: modalReducer
modal is an object with the following properties: showModal=false, user=undefined, image=undefined
When a div containing picture is clicked, the action is being dispatched that sets showModal to true (with username and url image link as arguments).
export var openModal = (user, image) => {
return {
type: 'OPEN_MODAL',
user,
image
}
}
For the actual modal I use a foundation reveal modal and in its render method I check if modal.showModal == true and use jQuery to open it up.
Now, toggling the modal works as charm but I cannot use the modal.user and modal.image properties inside of the render method as it prints the following error message:
Uncaught Error: findComponentRoot(..., .0.2.0.0.1): Unable to find element. This probably means the DOM was unexpectedly mutated (e.g., by the browser), usually due to forgetting a when using tables, nesting tags like , , or , or using non-SVG elements in an parent. Try inspecting the child nodes of the element with React ID ``.
I'm almost certain the problem lies within the ProfileModal.jsx component. Any idea what I'm doing wrong?
export class ProfileModal extends React.Component {
componentDidMount () {
var elem = new Foundation.Reveal($('#profile-modal'));
$('#profile-modal').on('closed.zf.reveal',()=>{this.props.dispatch(actions.hideModal())});
}
render () {
var {modal} = this.props;
if (modal.showModal) {
$('#profile-modal').foundation('open');
}
return(
<div>
<div id="profile-modal" className="reveal large">
<div className="modal-container">
<div className="modal-picture" style={{backgroundImage: `url(${modal.image})`}}></div>
<p>{modal.user}</p>
...

Iron meteor's Route doesn't fire rendered event of the template

Here's my case. I'm building an template that should render a chart based on the some data that I can get by identifier.
The example that I will show here is the simplified version of my code that fully discribe my problem.
Here is my HTML:
<head>
<title>example</title>
</head>
<body>
</body>
<template name="layout">
First text
Another text
{{> yield}}
</template>
<template name="example">
<span id="text">Basic Text</span>
</template>
And JavaScript:
if (Meteor.isClient) {
Router.configure({
layoutTemplate: 'layout'
});
Router.route('/:text', function() {
this.render('example', {
data: this.params.text
});
});
Template.example.rendered = function() {
$('#text').html(this.data);
}
}
This code renders whatever you put in url into "p" tag. If you will go over the first link you will get the text "firstText". But after it if you will go over another link the text will be the same. The text will be changed if only will you reload the page.
That is because when you render the template via the iron:router's method this.render('template') the meteor creates and renders this template that cause the fire of the created and rendered events, but if you go to the other url from the same router, the meteor doesn't destroy this template and recreates him, but just change the data. So the rendered event doesn't fire on change of the URL.
I can use only the rendered event and not the helpers because from helpers I can't get element with JQuery.
Now I'm using the solution where I'm wrap all the logic in rendered event into the Tracker.autorun() and use Session.set('text', this.params.text) in the router and Session.get('text') in the autorun function to rerender the text every time the URL will change. But this solution gives additional problems. And I think that Router's this.render('templateName') should fire the rendered event.
Could you please help me to make the first variant work without reactive data. Maybe there are some solutions that can truly rerender the template?
Meteor avoids re-rendering templates as much as possible and it is great because it makes code faster. The key here is to use reactivity. So you can write something like that in html:
<template name="example">
<span id="text">{{text}}</span>
</template>
and in js file:
Template.example.helpers({
text: function() {
return this;
}
});
You don't need rendered function for this and you don't need jQuery.
And if you want you can access element from helper with jQuery.
In rendered
Template.example.rendered = function() {
this.rendered = true;
}
and then in helper
whateverHelper: function() {
var tmpl = Template.instance;
tmpl.rendered && tmpl.$('#something').makeFun();
}

Ember Collapsible Container

I'm using Ember.js with handlebars and I need to make a div within my page collapse/expand when clicked. I know how to do this in jQuery, but I can't use any jQuery. Does anyone know how to accomplish this? Also I don't want to just toggle a hide attribute, I need the full sliding up and down feature for collapsing. If anyone has any ideas, I'd really appreciate it.
Thanks
Clicking on your view will cause a click event to be triggered. You can code your animation in any manner you want inside a click event handler in your view:
CollapsableView = Ember.View.extend({
click : function(event) {
this.$().toggle('fast');
}
})
The proper way of doing this in Ember is via the awesome Liquid Fire addon.
The outline:
Install Liquid Fire into your project.
Define a transition like this:
this.transition(
this.hasClass('transition-spoiler'),
this.toValue(true),
this.use('toDown'),
this.reverse('toUp')
);
In your controller/component, create a property spoilerIsVisible and a toggleSpoiler property:
spoilerIsVisible: false,
actions: {
toggleSpoiler: function() {
this.toggleProperty('spoilerIsVisible');
}
}
In your page/component template, create a button and a spoiler wrapper like this:
<button {{action 'toggleSpoiler'}}>
{{if spoilerIsVisible 'Show spoiler' 'Hide spoiler'}}
</button>
{{#liquid-if spoilerIsVisible class="transition-spoiler"}}
<p>Dumbledore dies</p>
{{/liquid-if}}
Note that you can wrap steps 3-4 into an x-spoiler component or something.
I do something similar, but with a tree-structure. I have written a blog post about this previously here: http://haagen-software.no/blog/post/2012-05-05-Ember_tree
It has the features you need in it, in that it adds and removed elements from the DOM when the nodes are clicked on.
A working example can be seen in an app I am currently building here: https://github.com/joachimhs/EurekaJ/tree/netty-ember/EurekaJ.View/src/main/webapp

Categories

Resources