Add button with custom event in Filepond drop area - vuejs2

I want to add a button in drop area with custom event on it to trigger a modal.
<template>
<div id="app">
<file-pond
name="test"
ref="pond"
max-files="4"
label-idle="Drop files here... <button class=“Filepond—custom”>Search<\button>"
:allow-multiple="true"
accepted-file-types="image/jpeg, image/png"
:files="myFiles"
v-on:init="handleFilePondInit"
allowImagePreview ="false"
/>
</div>
</template>
Is there a way to do this?
I tried creating a plug-in on CREATE_VIEW filter but I wasn’t successful.
Edit: The problem with CREATE_VIEW or any other available filter is that they all are applied when the item(s) is added/updated.

There might be another workaround but I came up with this solution.
On Filepond initalization I was able to append the button and attached an event to it.
handleFilePondInit: function () {
// Filepond is initialized
const element = document.querySelector('.filepond--label-action');
const button = document.createElement('button');
button.type = 'button';
button.className = 'filepond--media-search-action';
button.innerHTML = 'Button Name'
button.addEventListener('click', () => {console.log('button clicked')});
element.appendChild(button);
},

Related

How to bind a click event to a button when component is mounted vue js?

I am using a third party app (vue slick carousel) and I need to bind a click event to below button
<button type="button" data-role="none" class="slick-arrow slick-next" style="display: block;">
<svg...</svg>
</button>
So everytime I click this button a function gets triggered. This is what I tried in mounted and created life cycle, but didn't bind click event to it.
// console.log(document.querySelector(".slick-next")); // this returns element stated above
document.querySelector(".slick-next").addEventListener("click", () => {
console.log("Works");
});
I tried using setAttribute hoped it works, but it didn't work either.
Any help is appreciated. Thank you in advance.
I suspect they're probably using stopPropagation on the button click inside the component then.
There might be another way around this depending on your needs:
<VueSlickCarousel #beforeChange="checkChange">
...
</VueSlickCarousel>
methods: {
checkChange(oldSlideIndex, newSlideIndex) {
if (newSlideIndex > oldSlideIndex) {
console.log("Next button clicked");
}
}
}
Another option might be to use the <template #nextArrow="{ currentSlide, slideCount }"></template> slot inside the Carousel tag and use your own button. You'd probably have to implement your own logic for setting the next slide if you went this route.
You must to use the events handling of vuejs. Vuejs have many events for multiple cases.
For example in your case, you can use the event v-bind:click or simply #click. In documentation of vue slick, show this examples, wich is essentially the same.
I attach an code snippet:
<template>
<VueSlickCarousel ref="carousel">
<div><h3>1</h3></div>
/*...*/
</VueSlickCarousel>
<button #click="showNext">show me the next</button>
</template>
<script>
export default {
methods: {
showNext() {
this.$refs.carousel.next()
},
},
}
</script>

Impossible to click on a specific button part of a class with vue-test-utils

I want to test an editable table with vue-test-utils. There are edit buttons for each row, and when an edit button is clicked, the table row expands and allow the user to input information.
Each edit button has the class "editAddress", this is what I've tried so far :
describe('Customers Addresses Table', () => {
let wrapper;
beforeEach(() => {
wrapper = mount(AddressesTable);
});
it('can edit an address',() => {
const firstEditAddressButton = wrapper.findAll('button.editAddress').at(0);
firstEditAddressButton.trigger('click');
console.log(firstEditAddressButton.html());
expect(wrapper.html()).toContain('Close');
});
});
The test fails because it doesn't seem the button has been clicked..
The html code of my table looks like this (I use bootstrap-vue table here):
<div class="panel panel-default">
<b-table>
Address Edition-->
<template v-slot:cell(name)="data">
<div>
<button class="editAddress" #click="data.toggleDetails(); buttonEditClicked(data.item)">{{ data.item.name }}</button>
</div>
</template>
</b-table>
</div>
After the edit button being clicked, the table should transform like this :
Maybe I am not fetching the first button of the class "editAddress" correctly, I don't have any idea..
Thanks for your help !
Try that
it('can edit an address', async () => {
const firstEditAddressButton = wrapper.findAll('button.editAddress').at(0);
firstEditAddressButton.trigger('click');
await wrapper.vm.$nextTick();
expect(wrapper.html()).toContain('Close');
});

Replace image with placeholder on src change

I have an image with a bound src value
<img :src="image.url">
When image.url gets updated, the old image stays in place until the new image is loaded. This can look a little weird as the new image lags behind the text details on change.
How can I replace the image with a loading indicator when the src property changes with vue.js?
I could add DOM manipulation with the code that triggers the change and that works, but I'd rather do it properly with vue bindings.
This should get you on the right track:
Have an imageLoading attribute in your data() function.
Set your :src as follows: <img :src="imageLoading ? ./myPlaceholder.png : image.url" />
$watch your image.url to set the loading image whenever it changes:
watch: {
'image.url': function() {
this.imageLoading = true;
}
Add an #load handler to your img tag to set imageLoading to false when the image loads: <img :src="imageLoading ? ./myPlaceholder.png : image.url" #load="imageLoading = false" />
Note on the #load handler - shamelessly stolen from this question, which does link to an example.
This is a basic image placeholder component that uses slots to display any placeholder content
<template>
<div class="image">
<img :src="src" #load="ready = true" v-show="ready">
<slot v-if="!ready" />
</div>
</template>
<script>
export default {
props: ['src'],
data: () => ({
ready: false
}),
watch: {
src () { this.ready = false }
}
}
</script>
to use it
<image-placeholder src="IMAGE_URL">
<b>PLACEHOLDER CONTENT HERE</b>
<p>Can be anything</p>
<img src="ANOTHER_IMAGE_URL" />
</image-placeholder>

Vue.js modal: How can I get response from modal?

I am using Vue.js modal package and I don't know how can I get response data out of my modal window. I created a component for my modal window. Component usage looks like this:
<MyModal :data="data"
#closed="modalClosed"/>
And I want to get data from the closed event. I open my modal with:
this.$modal.show('my-modal')
And close it with:
<button type="button" #click="$modal.hide('my-modal', {success: true})" class="delete mr-3" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
My modal is defined in MyModal component (I left out the html and script code):
<template>
<modal
name="my-modal"
transition="nice-modal-fade"
:delay="100"
:width="'100%'"
:height="'auto'"
:classes="['v--modal', 'col-xl-6', 'col-lg-6', 'col-md-8', 'col-sm-12', 'col-xs-12', 'offset-md-2', 'offset-lg-3', 'offset-xl-3']"
:scrollable="true"
:adaptive="true"
:maxHeight="100">
</modal>
</template>
The #closed hook works inside the modal but not outside where I need it. I don't have any experience in Vue.js, and this is my first attempt at modal windows, so I don't really know what am I missing here, and the documentation is really bad.
If you want it to work outside of your modal component you could chain an event.
<button #click="show">show modal</button>
<modal
name="my-modal"
#closed="closedEvent"
>
modal content
</modal>
Then down in your methods obj you can emit another event from your #closed event
methods: {
closedEvent() {
this.$emit('chainClosedEvent', this.componentDataGoesHere)
}
}
Check out this fiddle https://jsfiddle.net/caseyjoneal/sm6gu1je/299/
If you end up needing your modal data throughout your app you should look at vuex
Check out the events section: there is a closed event you can hook into.
https://www.npmjs.com/package/vue-js-modal#events
Have you tried using "before-close" event handler instead of "close"?
As I've understood this component, on "close" event it doesn't $emit any data from component, and because of that, you can't get it in parent-component.
I just tried out this package locally. The #closed hook does work as designed. The markup I used is below
<button #click="show">show modal</button>
<modal
name="my-modal"
#closed="closedEvent"
>
modal content
</modal>
You definitely need a name attribute on the modal component. It does not appear that you have that.
If someone is looking for a solution, I coded as below:
In the view that calls the modal:
Define the modal components and the event that will be raised:
<template>
...
<grupo-alteracao #fechado="grupoAlteracaoFechado"/>
<grupo-novo #fechado="grupoNovoFechado"/>
</template>
<script>
...
import GrupoAlteracao from '#/views/GrupoAlteracao.vue'
import GrupoNovo from '#/views/GrupoNovo.vue'
export default {
name: 'grupo',
components:{
GrupoAlteracao,
GrupoNovo,
},
...
methods: {
novo: function(){
this.$modal.show('grupo-novo');
},
alterar: function(){
this.$modal.show('grupo-alteracao',this.selecionado);
},
grupoAlteracaoFechado(event){
this.pesquisarGrupos();
},
grupoNovoFechado(event){
this.pesquisarGrupos();
},
}
In the modal raise the event (fechado):
<template>
<modal name="grupo-alteracao"
:width=largura
:height="268"
:clickToClose="false"
#before-open="beforeOpen"
#before-close="beforeClose"
style="z-index: 49">
...
</modal>
</template>
...
...
methods: {
beforeOpen (event) {
this.grupo = event.params;
},
beforeClose (event) {
this.$emit("fechado");
},
I hope this helps.

How to focus and activate a vue multiselect?

When the user double-clicks this:
<div
class="open-select"
v-if="!editable"
#dblclick="editable=true">{{ name }}
</div>
I'd like this multiselect to be open and focused:
<multiselect
v-else
v-model="name"
:options="names"
track-by="id"
tabindex="0"
autofocus
#select="editable=false"
></multiselect>
The double-click event shows the multiselect element fine, but the multiselect still requires the user to click it to open. I'd like it to open automatically after appearing.
Things I've tried:
focusing the multiselect:
tabindex="0"
autofocus
When I try to select the focused item in jQuery, $(':focus')[0], I get 'undefined'
Heyo!
You can put a ref on the component and then trigger focus which will open the dropdown.
<multiselect ref="vms" v-bind="yourAttributes" />
And then in your created hook you add
this.$refs.vms.$el.focus()
A simplest solution - Toggle Vue Multiselect dropdown
You can use 2 events (#open, #close) on VueMultiselect
anda ref in multiselect
like
ref="multiselect"
keep in
data(){
isOpen: false
}
then add to the 2 events
#close="isOpen = false"
#open="isOpen = true"
and use a method
toggle() {
if (this.isOpen) {
this.$refs.multiselect.$el.blur()
this.isOpen = false
} else {
this.$refs.multiselect.$el.focus()
this.isOpen = true
}
}
Finally figured out how to do this (ref didn't work for me):
STEP 1: I was focusing on the wrong element.
So a vue-multiselect element is structured like this (shorthand to only show important parts):
<div class="multiselect"> // <= This is the element to focus on
<div class="multiselect__tags">
<input> // <= Not the input
</div>
</div>
Typically you want to put your tabindex on the input, instead you should put it on the parent with a class of multiselect. This also goes for things like jQuery's focus(). So...
No: $('.multiselect input').focus()
Yes: $('.multiselect').focus()
STEP 2: Correcting tabindex.
Another issue is when vue-multiselect puts a tabindex="-1" on all .multiselect elements. This removes them from the natural order of tabindexes, so you need to reassign all the tabindexes:
In mounted and updated (if necessary) you need code to reassign all the tabindexes:
mounted: function() {
$(document).ready(()=>{
// you may need to delete all tabindexes first.
$('[tabindex]').each( (i,v) => {
$(v).removeAttr('tabindex');
return true;
});
// add new tabindexes
$('input, textarea, button').each(( i,v ) => {
var isMultiSelect = $(v).hasClass('multiselect__input');
if(isMultiSelect){
$(v).parents('.multiselect:first').attr('tabindex', i + 1);
else{
$(v).attr('tabindex', i + 1);
}
});
});
}