How to change <ion-item> into <ion-input> by clicking on the <ion-item>? - ionic4

HTML code:
<ion-list>
<ion-item *ngFor = "let item of items;let i=index" >{{item.itemName}}</ion-item>
</ion-list>
I wish to convert any particular ion-item into an input field when a user clicks on the item field. Is there a way to implement it?

With angular you can do a combination of template checks and listening for user click on <ion-item>.
// you must map itemVisible to true for each item you have.
// I don't know what kind of values you're dealing with
items = [
{
itemName: 'item1',
itemVisible: true
},
{
itemName: 'item2',
itemVisible: true
},
{
itemName: 'item3',
itemVisible: true
}
];
constructor() {}
<ion-list>
<ion-item *ngFor="let item of items"
(click)="item.itemVisible = !item.itemVisible">
<div *ngIf="item.itemVisible; else ionInput">
{{item.itemName}}
</div>
<ng-template #ionInput>
<ion-input placeholder="{{item.itemName}}"></ion-input>
</ng-template>
</ion-item>
</ion-list>

Related

Vue Element UI Select Option Bug

Element UI
I have fetch the data from backend and use it as select option which does not come with value object, but
when I try to select any item in select option, the select option show all item list selected, but the model value is correct
Follow Code Fetch the Bug
<el-option
v-for="item in options"
:key="item.key"
:label="item.label"
:value="item">
</el-option>
This was the Sample Bug I created...
https://codepen.io/JackarooNg/pen/qBRdqgO
The problem is with model name is matched with select option's property of key and label
Step 1: Script will be like
<script>
new Vue({
el: "#app",
data: function () {
return {
visible: false,
options: [
{
value: "Option1",
label: "Option1"
},
{
value: "Option2",
label: "Option2"
},
{
value: "Option3",
label: "Option3"
}
],
options1: [
{
value: "Option1",
label: "Option1"
},
{
value: "Option2",
label: "Option2"
},
{
value: "Option3",
label: "Option3"
}
],
value: "",
value1: ""
};
}
});
Step 2: HTML template will be
<div id="app">
<el-button #click="visible = true">Button</el-button>
<el-dialog :visible.sync="visible" title="Hello world">
<p>Try Element</p>
</el-dialog>
<el-select v-model="value" placeholder="Select">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item"
>
</el-option>
</el-select>
{{value}}
<el-select v-model="value1" placeholder="Select">
<el-option
v-for="item in options1"
:key="item.value"
:label="item.label"
:value="item"
>
</el-option>
</el-select>
{{value1}}
</div>
DEMO

Toggle button text on a loop VUE

I have a loop with products, each with a product card.
I want to be able to toggle the button when clicked from Add to cart to Remove from cart.
The problem is all of the products buttons toggle at the same time, and I wan't ONLY the individual product card buttons to be toggled referencing each individual product.
In my HTML
<div v-for="product of products" :key="product.id">
<span class="btn btn-primary mt-5 modal-toggle-btn" #click="addGift(product, text, 'index')" v-show="!isAdded">Añadir a la box</span>
<span class="btn btn-primary mt-5 modal-toggle-btn" #click="removeGift(product, 'index')" v-show="isAdded">Quitar de la box</span>
</div>
Vue data
isAdded: false
My Vue methods
addGift(product, index){
this.campaign.selectedproducts.push({name: product.name });
this.isAdded = true
},
removeGift(product, index){
this. campaign.selectedproducts.splice(index, 1)
this.isAdded = false
},
My suggestion is to:
Divide the product buttons as an individual component.
Use addedIds as an array to store added product ids instead of isAdded boolean.
Communicate parent and child click events with Vue event handling.
Store clicked product id in to the addedProductId on click events.
Check against addedProductId to make sure a product was added or
not in child component.
Example:
ProductButtons.vue (child component)
<template>
<div>
<span class="btn btn-primary mt-5 modal-toggle-btn" #click="addGift" v-show="!isAdded">Añadir a la box</span>
<span class="btn btn-primary mt-5 modal-toggle-btn" #click="removeGift" v-show="isAdded">Quitar de la box</span>
</div>
</template>
<script>
export default {
name: "ProductButtons",
props: {
product: { type: Object, required: true },
addedIds: { type: Array, required: true },
},
computed: {
isAdded() {
return this.addedIds.indexOf(this.product.id) > -1;
},
},
methods: {
addGift(){
this.$emit('addGift', this.product);
},
removeGift(product){
this.$emit('addGift', this.product);
},
}
}
</script>
In Your HTML
<template v-for="product of products" :key="product.id">
<product-buttons :product="product" :addedIds="addedIds" #addGift="addGift" #removeGift="removeGift"></product-buttons>
</template>
Vue data
addedIds: []
Your Vue methods
addGift(product){
this.campaign.selectedproducts.push({name: product.name });
// save product id as an added id
const index = this.addedIds.indexOf(product.id);
if (index === -1) {
this.addedIds.push(product.id);
}
},
removeGift(product){
this.campaign.selectedproducts.splice(index, 1);
// remove product id
const index = this.addedIds.indexOf(product.id);
if (index > -1) {
this.addedIds.splice(index, 1);
}
},

Vue on input text, changes background color for both input fields

I am using bootstrap-vue to display modal. Once the modal is opened using OPEN MODAL BUTTON, it displays two input fields. When I add a text to one of the input field, it changes color on both input fields. Is there a way to change color for the field which consists of datatype only?
View
<div id="app">
<b-modal id="modal-center" ref="modalRef" centered title="DISPLAY MODAL" v-bind:hide-footer="true">
<b-row class="my-1">
<b-col sm="11">
<div v-for="(listings, index) in list2" :key="index">
<br/>
<b-form-input v-model="listings.rfidState1" placeholder="insert text" v-on:input="gotText()" :style="isChanged ? { 'background-color': '#33FF90' } : null" ></b-form-input>
</div>
</b-col>
</b-row>
<br/>
<b-row>
<b-col><b-button block variant="info" v-on:click="hidemodal();">UPDATE</b-button></b-col>
<br/>
</b-row>
<br/>
</b-modal>
<b-button block v-b-modal.modal-center variant="info">OPEN MODAL</b-button>
</div>
Script
new Vue({
el: "#app",
data: {
list2: [
{ text: "Learn JavaScript", done: false },
{ text: "Learn Vue", done: false }
],
isChanged: false
},
methods: {
hidemodal(){
this.$refs['modalRef'].hide()
},
gotText(){
this.isChanged = !this.isChanged;
}
}
})
Here is my code on jsfiddle
https://jsfiddle.net/ujjumaki/wgr3m6td/30/
Yes this can be done with a few changes.
First, remove isChanged from your data, and add it as a property to each of your list2 objects, so each object looks like this:
{ text: "Your text", done: false, isChanged: false }
next, your :style="isChanged ? ", should instead be:
:style="listings.isChanged ? "
next up, your v-on:input="gotText" should take the index as a parameter like so:
v-on:input="gotText(index)"
last, your gotText method should receive the index and use it to update isChanged:
gotText(index) {
this.list2[index].isChanged = !this.list2[index].isChanged
}
This should answer your question, but if you want some of the behaviour changed ask away.
Edit:
As suggested by n-smits, your data in the vue instance should not be an object, but a function that returns an object like this:
data(){
return {
list2: [..]
}
}
I recommend that you read his comment to understand why this is necessary.

vuejs semantic ui - drop down not displaying on arrow click

I'm faced with an issue where my semantic drop down in my vue project won't activate when clicking on the arrow icon but works when I click on the rest of the element. The drop down also works when I set the dropdown to activate on hover, but just not on click. Solutions I've tried:
tested if the dynamic id are at fault
tested if the back ticks are confusing things
placed the values directly into the semantic drop down
Aside from the dropdown not activating, the code below works as intended and brings back the selected value to the parent component and can be displayed.
Dropdown.vue:
<template>
<div class="ui selection dropdown" :id="`drop_${dropDownId}`">
<input type="hidden" name="gender" v-model="selected">
<i class="dropdown icon"></i>
<div class="default text">Gender</div>
<div class="menu">
<div class="item" v-for="option in options" v-bind:data-value="option.value">
{{ option.text }}
</div>
</div>
</div>
</template>
<script>
export default {
data: function () {
return {
selected: {}
}
},
watch: {
selected: function (){
this.$emit("dropDownChanged", this.selected)
}
},
props: {
options: Array, //[{text, value}]
dropDownId: String
},
mounted () {
let vm = this;
$(`#drop_${vm.dropDownId}`).dropdown({
onChange: function (value, text, $selectedItem) {
vm.selected = value;
},
forceSelection: false,
selectOnKeydown: false,
showOnFocus: false,
on: "click"
});
}
}
</script>
The component usage:
<vue-drop-down :options="dropDownOptions" dropDownId="drop1" #dropDownChanged="dropDownSelectedValue = $event"></vue-drop-down>
The data in the parent:
dropDownOptions: [
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
],
dropDownSelectedValue: ""
Here is a fiddle of the above but simplified to use a flatter project. However the problem doesn't reproduce :(
https://jsfiddle.net/eywraw8t/210520/
I'm not sure what is causing your issue (as the examples on the Semantic Ui website look similar), but there is a workaround. For you arrow icon:
<i #click="toggleDropDownVisibility" class="dropdown icon"></i>
And then in the methods section of your Vue component:
methods: {
toggleDropDownVisibility () {
$(`#drop_${this.dropDownId}`)
.dropdown('toggle');
}
},

Accessing siblings elements in a v-for

New to Vuejs 2, need a bit of help to understand how this would be done.
So, I have a template that looks like the following:
<template>
<div class="wrapper">
<div class="item" v-for="item in items">
<div class="item">
<div class="title">{{ item.title }}</div>
<div class="action">
<a href="#" #click.prevent="editSettings(item, $event)">
Click Me
</a>
</div>
</div>
<div v-if="showSettings" class="settings">
<!-- Settings component for this item. -->
<settings-panel item="item"></settings-panel>
</div>
</div>
</div>
</template>
The scripts looks like this:
export default {
data() {
return {
items: [
// This data is from an API usually and only
// shown here for example purposes
{ id: 1, title: 'Title 1' },
{ id: 2, title: 'Title 2' },
{ id: 3, title: 'Title 3' },
{ id: 4, title: 'Title 4' }
],
showSettings: false
};
},
methods: {
editSettings(item, event) {
// Only show the clicked items settings, not all
this.showSettings = !showSettings;
}
}
}
What is the easiest and cleanest approach to only showing the settings panel for the clicked item? Right now, if I click the Click Me settings, all settings open up. The data listed in the code is only there for example, but is coming from an API so I don't have much to do with the manipulation of that data.
Can anyone help lead me in the right direction?
Instead of using showSettings add a selectedItem.
export default {
data() {
return {
items: [
// This data is from an API usually and only
// shown here for example purposes
{ id: 1, title: 'Title 1' },
{ id: 2, title: 'Title 2' },
{ id: 3, title: 'Title 3' },
{ id: 4, title: 'Title 4' }
],
selectedItem: null
};
},
methods:{
selectItem(item){
if (this.selectedItem === item) this.selectedItem = null
else this.selectedItem = item
}
}
}
And modify your template to set the selectedItem when the item is clicked and show the settings only if the selectedItem is the current item.
<template>
<div class="wrapper">
<div class="item" v-for="item in items">
<div class="item">
<div class="title">{{ item.title }}</div>
<div class="action">
<a href="#" #click.prevent="selectItem(item)">
Click Me
</a>
</div>
</div>
<div v-if="selectedItem === item" class="settings">
<!-- Settings component for this item. -->
<settings-panel item="item"></settings-panel>
</div>
</div>
</div>
</template>
The above will show the settings for the clicked item if the currently selected item is not the item that was clicked. If the currently selected item is the one that was clicked, it will hide the settings.