I want to show the update button when the userId matches with one of the previous users & if the userId & one of the previous users doesn't match then it will show the submit button.
I am trying this way---
new Vue({
el: '#app',
data: function() {
return {
userId:1,
previousUsers:[1,2],
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(previousUser,i) in previousUsers" :key="i" class="text-center mt-3">
<button v-if="previousUser == userId" class="btn btn-primary" #click="update">Update</button>
<button v-if="previousUser == !userId" class="btn btn-primary" #click="add">Submit</button>
</div></div>
In my way the submit button doesn't show if I change the userId to "3". How to solve this?
You are looping through all the previous users and making comparisons with the current user, so you will display one button for each user. If this is your intent you are just writing the second condition in a wrong way: instead of previousUser == !userId it should be previousUser != userId, but this way changing the userId to 3 will make the program render 2 submit buttons, because each previous user you are cycling through is different from the current user id.
Instead, if you want to show just ONE button, and the button should be update if userId is in the previous user ids array and submit otherwise, I suggest you to use a computed property to decide which button to render, and not to use a v-for. For example:
new Vue({
el: '#app',
data: function() {
return {
userId:1,
previousUsers:[1,2],
}
},
computed: {
isUserInPreviousUsers() {
return this.previousUsers.indexOf(this.userId) >= 0;
}
}
});
<button v-if="isUserInPreviousUsers" class="btn btn-primary" #click="update">Update</button>
<button v-else class="btn btn-primary" #click="add">Submit</button>
Related
I have a textbox
<div>
<b-form-textarea
id="textarea"
v-model="text"
placeholder="Certification text "
rows="5"
max-rows="6"
></b-form-textarea>
</div>
And two buttons
<b-button variant="primary" class="btn btn-primary btn-lg top-right-button mr-1">Save</b-button>
<b-button variant="info" class="btn btn-info btn-lg top-right-button mr-1">Add Name</b-button>
When the user is typing and in between if he clicks Add Name button {name} should be placed in the textbox (Where ever the cursor is).
How can i implement it?
You can add a ref to your textarea, and access the selectionStart property, which contains the placement of the cursor.
You can then use this index to splice the given text into the textarea's text at the given position.
And since clicking the button will lose the focus of the input, you can add it back by calling the focus method on the ref, along with setting the selectionStart and selectionEnd so the cursor is where it left off.
new Vue({
el: "#app",
data() {
return {
text: ""
};
},
methods: {
addName() {
const { text } = this;
const textarea = this.$refs["my-textarea"].$el;
const index = textarea.selectionStart;
const name = "{name}";
this.text = `${text.substring(0, index)}${name}${text.substring(
index
)}`;
textarea.focus();
setTimeout(() => {
textarea.selectionStart = index + name.length;
textarea.selectionEnd = index + name.length;
});
}
}
});
<script src="https://unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.17.3/dist/bootstrap-vue.js"></script>
<link href="https://unpkg.com/bootstrap#4.5.2/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue#2.17.3/dist/bootstrap-vue.css" rel="stylesheet" />
<div id="app">
<b-form-textarea ref="my-textarea" v-model="text" placeholder="Certification text" rows="5" max-rows="6">
</b-form-textarea>
<b-btn variant="primary" size="lg" #click="addName">
Add Name
</b-btn>
</div>
I have create a set of pairs of divs, that use the v-for method to get data from a set of dummy objects in an array. The goal is for each pair of divs when I click on the visible div it opens the corresponding relevant div. At the moment my function which I have attached as a property of a method object only opens the invisible div of the first pair of divs even if I click on the 3rd visible div it still displays the invisible div. i am using the vue framework.
I have attached pictures of my code then the actual code.
[The div I am trying to open is session-on-click details atm it is opening only that for the first index][1]
<div class = "rowuserlog" id="log-container" v-for="session in sessions" :key="session.id"
>
<div id="log-container-user-row-1">
<div id="profile-log-title" #click="logToggler()"> {{session.name}} </div>
<div id="profile-log-date"> {{session.date}}</div>
<div id="user-log-metric-container">
<div id ="user-log-hr" class="log-metric">{{session.hr}}</div>
<div id ="user-log-time" class="log-metric"> {{session.time}}</div>
<div id ="user-log-meters" class="log-metric"> {{session.distance}} </div>
<div id="session-onclick-details">
<div id="log-comments">
{{session.comments}}
</div>
<div id="log-edit-buttons">
<button id="log-save" class="log-edit-button"> Save </button>
<button id="log-delete" class="log-edit-button"> Delete </button>
<button id="log-cancel" class="log-edit-button"> Cancel </button>
<button id="log-edit" class="log-edit-button"> Edit </button>
</div>
</div>
```
My method
The toggler is the method I want:Here is the code
methods:{
logToggler () {
const extraInfoLog = document.getElementById("session-onclick-details");
return extraInfoLog.style.display="block";
}
]
[2]
[1]: https://i.stack.imgur.com/ddrYo.png
[2]: https://i.stack.imgur.com/evriF.png
data() {
return {
sessions:[
{ name:'test',
value:false,
id:1
},
{ name:'test1',
value:false,
id:2
},
{ name:'test2',
value:false,
id:3
}
]
}
}
methods:{
logToggler(_index) {
for(let index=0;index<sessions.length;index++) {
if(index == _index)
sessions[index].value = true
else
sessions[index].value = false
}
}
}
Template
<div class = "rowuserlog" id="log-container" v-for="(session,index) in sessions" :key="session.id"
>
<div id="profile-log-title" #click="logToggler(index)" v-if="session.value"> {{session.name}} </div>
I want to make multiple 'in-place' editable date fields in table rows.
An example for a single field below works.
I show the currentdate (oldDate) as a label. User clicks on 'Change', an input field appears, after editing the user can Accept or Cancel.
https://jsfiddle.net/asrajan55/qv6crg84/
<div id="root">
<label>Test Date:</label>
<span v-show="!makeEditable"> {{ oldDate }} </span>
<span v-show = "makeEditable">
<input type="date" v-model="newDate" required=""/>
<button #click="acceptClicked">Accept</button>
<button name="cancel" #click="makeEditable=false">Cancel</button>
</span>
<button v-show="!makeEditable" #click="makeEditable=true" >Change</button>
</div>
new Vue({
el: "#root",
data: {
oldDate: '2019-02-04',
newDate: '2019-02-04',
makeEditable: false,
},
methods: {
acceptClicked(){
if (this.newDate!='') {
this.oldDate=this.newDate;
this.makeEditable=false;
}
}
}
});
However if I try multiple(2) fields the click event fires (sometimes) but nothing seems to happen. No errors in console. Also the Vue debugger in the browser does not immediately update the changed fields. Please help. I am desperate and pulling my hair out!
https://jsfiddle.net/asrajan55/9uhkr4w0/3/
<div id="root">
<div v-for="(item,index) in oldDates">
<label for="">Test Date:</label>
<span v-show="!editables[index]">{{item}}</span>
<input v-show="editables[index]" type="date" v-model="oldDates[index]"/>
<button v-show="editables[index]">Accept</button>
<button v-show="editables[index]" #click="editables[index]=false">Cancel</button>
<button v-show="!editables[index]" #click="makeEditable(index)">Change</button>
<hr />
</div>
</div>
new Vue({
el: "#root",
data: {
oldDates: ['2019-01-04', '2019-02-04'],
newDates: ['2019-01-04', '2019-02-04'],
editables: [false, false]
},
methods: {
makeEditable(index) {
alert(index);
this.editables[index] = true;
}
}
});
The problem was that you were mutating the array in place,
creating a new array reference and passing it would solve the issue
fixed here : https://jsfiddle.net/e3L2zcna/
makeEditable(index) {
this.editables = this.editables.map((val,i) => i===index || val);
}
Try using this.$set(this.editables, index, true);
Vue can't detect changes to arrays if you directly access an element using []. Read about it here:
https://vuejs.org/2016/02/06/common-gotchas/#Why-isn%E2%80%99t-the-DOM-updating
Currently I am using Vuejs2 to generate listing for image upload, which will show preview image after select an image file, here is my code written in codepan with Vuejs2:
https://codepen.io/anon/pen/MELZKe
<div v-for="(image, index) in images" :key="index">
<div class="image-upload">
<label v-bind:for="'cover-upload-' + index">
<img src="http://via.placeholder.com/100x100" width="100" class="preview-img"/>
</label>
<input v-bind:id="'cover-upload-' + index" v-bind:name="'slides[' + index + ']'" type="file" class="upload-preview" style="display:none">
</div>
<button type="button"
#click.prevent="removeImage(index)"
v-show="image_quantity > 1">
Remove
</button>
</div>
I created 2 file upload images, upload first image (will preview your image), delete the first preview image, but it will delete the last preview image instead of first one.
However, almost same coding but using Vuejs1, it will delete the first preview image instead of last one. Here is codepen with Vuejs1:
https://codepen.io/anon/pen/VMgqbG
I have no idea how to write such situation for Vuejs2 or I have to stick with Vuejs1?
Thanks.
Using the index of an array as the key is a bad idea. This is because indexes mutate. Use a proper key and your issue is resolved.
Think about the case in the original code where there are two images in the images array. At first, the index of image one is zero and the index of the second image is one. When you delete the first image, now the index of what was originally was the second image has changed to zero, but Vue has existing DOM elements for key zero that show the image for the former object that was at index zero. Since Vue has those DOM elements for key zero, it re-uses them and it appears as though the first image was not deleted.
console.clear()
new Vue({
el: '#content',
data: {
images: [{ name: '' , id: 1}],
},
computed: {
image_quantity: function () {
return this.images.length;
},
},
methods: {
removeImage: function (index) {
this.images.splice(index, 1);
},
addImage: function (event) {
event.preventDefault();
this.images.push({
name: '',
id: Math.max(...this.images.map(i => i.id)) + 1
});
}
}
});
function readURL(input, preview) {
if (input.files && input.files[0] && input.files[0].type.match('image.*')) {
var reader = new FileReader();
reader.onload = function (e) {
$(preview).attr('src', e.target.result);
}
reader.readAsDataURL(input.files[0]);
}
}
$(document).on('change', '.upload-preview', function () {
readURL(this, $(this).prev().find('.preview-img'));
});
<div id="content">
<div v-for="(image, index) in images" :key="image.id">
<div class="image-upload">
<label v-bind:for="'cover-upload-' + index">
<img src="https://via.placeholder.com/100x100" width="100" class="preview-img"/>
</label>
<input v-bind:id="'cover-upload-' + index" v-bind:name="'slides[' + index + ']'" type="file" class="upload-preview" style="display:none">
</div>
<button type="button"
#click.prevent="removeImage(index)"
v-show="image_quantity > 1">
Remove
</button>
</div>
<button type="button" v-on:click="addImage">Create New</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
First question on stack overflow, I apologize if I am asking in the wrong place. New to Vue and been trying for several days to finish a small project. I've simplified it but here it is. I want to be able to enter as many customer names as I need, and then be able to add as many customer's childrens names as I need. So an array of customers with a nested array of children. I can get the customers to add, but I cannot figure out why I cannot push a new element into the children's array. Here is my code.
new Vue ({
el: '#app',
data: function () {
return {
formdata: [],
fields: [{
name: '',
childs: [{
cname: '',
}]
}],
};
},
methods: {
addRow: function() {
this.fields.push({
name: "",
childs: [{
cname:'',
}],
});
},
addChild: function() {
this.child.push({
});
},
},
});
And my html
<div id="app">
<button class="btn btn-success" #click="addRow">Add</button>
<div v-for="field in fields" >
<div class="input-group">
<input type="text" placeholder="Name" class="form-control" v-model="field.name">
</div>
<div v-for="child in field.childs" >
<div class="input-group">
<input type="text" placeholder="Child" class="form-control" v-model="child.cname">
<div class="input-group-btn">
<button class="btn btn-success" #click="addChild">Add</button>
</div>
</div>
</div>
</div>
</div>
Again, the problem is that i can push a new "name" to the fields array, but i cannot push a new child into the fields child array. I have been trying every permutation of child childs field fields etc, trying to find how to reference that array. Any help would be greatly appreciated!
In your addChild method, you need to be accessing the childs property of the relevant field. Currently, you are trying to access the childs property of the Vue instance, which doesn't exist.
You should pass the relevant field to the addChild method like so:
<button class="btn btn-success" #click="addChild(field)">Add</button>
And then update your addChild method to reference the childs array of the field passed in:
addChild: function(field) {
field.childs.push({});
}