How to show a modal(1) when user click buttons(4button with 1modal) - simplemodal

When I click add button I want to show input in React. The problem is add buttons are multiple. Do I need to give id manually?
my li component
<div className="content-children">
{props.showmodal ? (input modal) : (add btn)
}
</div>
my ul component
<ul>
<Lists
setshowmodal={setshowmodal}
showmodal ={showmodal}
/>
<Lists
setshowmodal={setshowmodal}
showmodal ={showmodal}
/>
</ul>

you are having two modals. Imagine modals are like screens or routes or fullsize-webpage, they show one at a time. You are using two modals like a screen. (I do use screens as modals). I might do something like this.
const [modal,setModal] = useState('');
const closeModal = ()=> setModal('');
return (
<ul>
<List modal={modal} onClick={() => setModal("one")} />
<List modal={modal} onClick={() => setModal("two")} />
</ul>
);
// Li component
return modal === "one" ? <Li /> : <Btn />;

Related

Add button with custom event in Filepond drop area

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);
},

Pass value from v-for input components with ref to parent in Vue3

I've been struggling a wile with this and would apreaciate some assistance.
I have a Vue3 child component that contains two input fields.
Child
<template>
<label>
<span>asset value</span>
<input type="number" :value="value" />
</label>
<label>
<span>target percentage</span>
<input type="number" :value="targetPercentage" />
</label>
</template>
There is a button in my main component to add this component unlimited times to the template.
I am trining to use the Composition API to get the values from those input fields via ref.
Parent
setup() {
// List of predefined assets
const assetList = reactive([
{
title: 'Position 1',
value: '',
targetPercentage: '',
}
]);
const assetsRefs = ref([]);
// Make sure to reset the refs before each update.
onBeforeUpdate (() => {
assetsRefs.value = [];
})
onUpdated (() => {
console.log(assetsRefs)
})
return {
assetList,
assetsRefs,
};
}
In the template of my main component I render those assets like the following
Parent
<template>
<div>
<Asset v-for="(asset, index) in assetList"
:key="index"
:value="asset.value"
:targetPercentage="asset.targetPercentage"
:ref="element => { assetsRefs[index] = element }"
/>
<button #click="addAsset">Add New Position</button>
<button #click="onSubmit">Calculate</button>
</div>
</template>
What I am trying to achive is, that there is some sort of two way binding between the parent and the child components. I obviously can't use v-model in my child components, because I already use props to bind the predefined values from the assetList (first code block).
I already found good examples for todo lists with refs and v-for or for submitting forms so that I could render multiple assets. But I never got some input field rendering with v-for and refs to actually get the input values.

How to wrap html components in Vue 3 to make use of same event handlers?

This is the code:
<q-avatar #click="redirectToHome" rounded color="green">
<img ... />
</q-avatar>
<q-toolbar-title #click="redirectToHome">
App
</q-toolbar-title>
what I want is a dummy component <></> where I can wrap these two components and use event handlers only once. Something like this:
<what-to-put-here #click="redirectToHome">
<q-avatar rounded color="green">
<img ... />
</q-avatar>
<q-toolbar-title>
App
</q-toolbar-title>
</what-to-put-here>
Is this possible in Vue 3 ?
[EDIT]
Obviously using a <div></div> will mess up the styles
You can create a wrapper component which renders the slots and binds handlers on them.
Something like this
// WrapperComponent
setup(props, { slots }) {
return () => {
if (slots.default)
return slots.default({ prop: someProp })?.map((node, i) => h(node, { ref: `target-${i}`, ...attrs, onClick: $event => console.log('clicked', $event.target)}));
};
}

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');
});

How to pass props from parent components to child components

I have three components namely Home.vue, Searchform.vue and Searchresults.vue respectively in my project.
Home.vue - is the view that i'm showing the other two components
Searchform.vue - is the component that hold the search input fields
Searchresults.vue - is the components that shows the result of search input in a "table form"
So when a user has make a search query and a result is render in the table. i make a method to get a row clicked into a data and pass an a props to Searchform.vue then bind the props on that on the home.vue. But the props data is not displaying on the Searchform.vue components resulting no showing on home.vue view.
Below is the code of two components and the home.vue
Home.vue
<template>
<div class="home">
<div class="example" v-if="isLoading === true">
<a-spin size="large" />
</div>
<Navbar />
<div class="container">
<SearchForm
v-on:search="search"
:selectedinterest="selectedinterest"
/>
<SearchResults
v-if="interests.length > 0"
v-bind:interests="interests"
v-bind:reformattedSearchString="reformattedSearchString"
/>
<ErrorMessage
v-if="interests.length < 0"
v-bind:interests="interests"
/>
<Footer />
</div>
</div>
</template>
Searchresults.vue
export default {
data() {
return {
selectedinterest: []
}
}
addSelection(interest) {
this.selectedinterest.push(interest.name))
}
}
And lastly the Searchform.vue that i want to pass the props to and bind it on the home.vue to get the data
export default {
name: 'SearchForm',
props: [
'selectedinterest'
]
}
Please how can i pass the props 'selectedinterest' to the home.vue and searchform.vue from the searchresults.vue components.
Props in - events out
Searchresults.vue
export default {
data() {
return {
selectedinterest: []
}
}
addSelection(interest) {
this.selectedinterest.push(interest.name));
this.$emit('onInterestSelected', this.selectedinterest);
}
}
Home.vue
...
<SearchResults
v-if="interests.length > 0"
v-bind:interests="interests"
v-bind:reformattedSearchString="reformattedSearchString"
v-on:onInterestSelected="updateSelectedInterest"
/>
<!-- don't forget create method updateSelectedInterest(updatedInterest) -->
...
One way to go could be to emit an event in your Searchresults.vue component inside the addSelection method.
addSelection(interest) {
this.selectedinterest.push(interest.name))
this.$emit('addedSelection', this.selectedinterest);
}
In your parent component you will listen to your event and use a method to store the event data and then pass it on as props to other components.
<SearchResults
v-if="interests.length > 0"
v-bind:interests="interests"
v-bind:reformattedSearchString="reformattedSearchString"
#addedSelection="addedSelectionTriggered"
/>
Using the addedSelectionTriggered method in your parent component you can store the emitted selectedinterest array and pass it on as props.