Add Html element in div vuejs - vue.js

I have been searching for 4 hours , cant even get my head to understand what to use
basically i want to add a new row (article tag) to a div element , everytime the user press the addbutton
in my method how can i pass this HTMLto the div :
<article class="col-md-11 col-md-offset-1 card" custom_attrib=atrrib_value> <span>
{{NEW VALUE}} - {{NEW VALUE_2}}
</span>
<span >
<button class="btn btn-theme btn-default btn-xs pull-left" #click="deleteItem" ><i class="fa fa-times inline"></i></button>
</span>
</article>
I have to say i need to put some custom attrib on the Article tag each time thats why i want to make a new tag on each request
if we take a look at this https://codepen.io/Pizzi/pen/GMOQXy
when pressing the + (add) a row drops , i want to do the same thing but the important part is the new row with article tag needs new custom_attrib and value everytime
another jsfiddle example : https://jsfiddle.net/50wL7mdz/17736/
instead of those input box will be my article with custom attrib and value

You make an array. When the user clicks "add new" you will append a new item to the array which contains HTML with two input fields. When you append it, Vuejs will re-render the HTML with the changed data.
// Vue.js
new Vue({
el: '#app',
data: {
items:[],
item:['NEW VALUE','NEW VALUE_2'],
},
created(){
this.items.push(this.item);
},
methods:
{
add()
{
this.item = ['</br><input type="text"/>','<input type="text"/></br>'];
this.items.push(this.item);
}
}
})
<h2>Vue.js</h2>
<div id="app">
<article class="col-md-11 col-md-offset-1 card" custom_attrib=atrrib_value>
<span v-for="item in items" ><span v-html="item[0]"></span> - <span v-html="item[1]"></span></span>
<span >
<button v-on:click="add" class="btn btn-theme btn-default btn-xs pull-left">
+
</button>
</span>
</article>
</div>
<!-- Vue.js -->
<script src="https://vuejs.org/js/vue.min.js"></script>

Related

Vue's reactivity not triggered when using Bootstrap 5's alert div

Vue's reactivity not triggered when using Bootstrap 5's alert div.
See my code:
<template>
<div>
<div
v-if="alertICDMsg!==''"
id="alertICDCode"
class="alert alert-info alert-dismissible fade show"
role="alert"
>
<i class="fa-solid fa-lightbulb" />
<strong> Note!</strong> <span v-html="alertICDMsg" />
<button
type="button"
class="btn-close"
data-bs-dismiss="alert"
aria-label="Close"
/>
</div>
<div class="input-group mb-3">
<div class="col-xs-1">
<input
id="ICDCode"
v-model="editing_icdCode"
class="form-control"
placeholder="ICD Code"
aria-label="ICD Code"
#input="ICDCodeSearchRequested"
>
</div>
<input
id="Diagnosis"
v-model="editing_diagnosis"
type="text"
class="form-control"
placeholder="Diagnosis"
aria-label="Diagnosis"
aria-describedby="basic-addon1"
list="icdsearchlist"
#change="SelectedDiagnosisTextOption"
#input="ICDTextSearchRequested"
>
<datalist id="icdsearchlist">
<option
v-for="(disease_option, index) in icd_diagnosis_options"
:key="index"
>
{{ disease_option }}
</option>
</datalist>
<button
id="btnAddDiagnoses"
href="#"
class="btn btn-primary mx-1"
#click="AddDiagnosis"
>
<i class="fal fa-plus-circle" />
</button>
<button
id="btnCopyPreviousDiagnoses"
href="#"
class="btn btn-primary BtnSaveGroup mx-1"
>
<i class="far fa-history" />
</button>
<button
id="quickbill"
class="btn btn-primary mx-1"
>
<i class="fas fa-search-plus" />
</button>
<button
id="clearICD"
class="btn btn-danger mx-1"
#click="ClearICDFields"
>
<i class="fad fa-times-circle" />
</button>
</div>
</div>
<template>
<script>
export default {
data() {
return {
alertICDMsg:"",
};
},
watch: {
alertICDMsg: {
handler(val) {
console.log(`Val for alertICDMsg changed to :${val}`);
},
immediate: true,
deep: true,
},
},
methods: {
ICDCodeSearchRequested() {
console.log(`Search by ICD code`);
this.alertICDMsg="Searching in ICD Code box will search only by code. To search by a diagnosis name, type in the Diagnosis box."
console.log(`alertICDMsg is ${this.alertICDMsg}`);
setTimeout(function() {
console.log(`Dismissing alert`);
this.alertICDMsg='';
console.log(`alertICDMsg is ${this.alertICDMsg}`);
}, 5000);
},
},
}
</script>
Console log:
Search by ICD code
SubClinicalBlock.vue?d801:291 alertICDMsg is Searching in ICD Code box will search only by code. To search by a diagnosis name, type in the Diagnosis box.
SubClinicalBlock.vue?d801:220 Val for alertICDMsg changed to :Searching in ICD Code box will search only by code. To search by a diagnosis name, type in the Diagnosis box.
SubClinicalBlock.vue?d801:293 Dismissing alert
SubClinicalBlock.vue?d801:298 alertICDMsg is
The problem is that after 5 seconds, though the value of the variable changes, the alert is still visible.
I checked some similiar questions, and have seen this happening when bootstrap's javascript wasnt loaded. But for me, Bootstrap v5.0.1 JS is being loaded from the CDN and appears in the sources tab in Chrome.
Try to change the function inside of setTimeout to arrow function like this
setTimeout(() => { // code here })
The this inside of setTimeout(function () => {}) reference to the wrong context (the function itself) instead of the Vue component.
The arrow function doesn't have the this binding so when you use the arrow function the this keyword will reference the Vue component and change the state.
More info: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

Set focus to first item in v-for using vue

I have a vue app and I'm trying to set the focus to the first item in my v-for list but struggling
HTML
<div class="input-group-append">
<button class="btn btn-light" type="submit" style="border: 1px solid lightgray" #click.prevent="findTest">
<i class="fas fa-search"></i>
</button>
</div>
<div v-if="this.Tests.length >= 2" class="list-group accList">
<a v-for="(test, i) in tests" :key="i" class="list-group-item list-group-item-action" :ref="i" :class="{ 'active': i === 0 }" #click.prevent="selectTest(test)">
{{ test.test1 }} ({{ test.test2 | capitalize }})
</a>
</div>
Note the word 'test' has replaced my actual values
I have tried using the following in my method which is called on button click but I keep getting get an error
methods: {
findTest() {
axios.get(END_POINT).then((response) => {
...SOMEOTHER CODE
//this.$refs.0.$el.focus()
//this.$refs.0.focus();
//this.$refs.a.$el.children[0].focus();
}
}
}
Error
I am relativly new to vue but I have been able to set my focus using:
this.$refs.[INPUT_NAME].$el.focus()
But it doesn't like me using a number
this.$refs.0.$el.focus() //0 being the index number
As WebStorm complains saying:
Expecting newline or semicolon
console.log(this.$refs)
When using v-for, ref maybe array of refs.
Template: use ref="tests" instead of :ref="i"
<a v-for="(test, i) in tests" :key="i" class="list-group-item list-group-item-action" ref="tests" :class="{ 'active': i === 0 }" #click.prevent="selectTest(test)">
{{ test.test1 }} ({{ test.test2 | capitalize }})
</a>
Script
this.$refs.tests[0]
I guess its undefined because you try to access the element while the v-for loop didnt finished its rendering
Try this:
methods: {
findTest() {
axios.get(END_POINT).then((response) => {
...SOMEOTHER CODE
this.$nextTick(()=> {
//put your code here
//this.$refs.0.$el.focus()
//this.$refs.0.focus();
//this.$refs.a.$el.children[0].focus();
})
}
}
}
Put your code into $nextTick() that should ensure that its get executed when the loop is done

Vue.js how to use radio buttons inside v-for loop

I'm trying to use radio buttons, so that users can choose one of the photos as their profile photo:
<ul v-for="p in myPhotos">
<li>
<div>
<div>
<div>
photo id: {{p.imgId}}
</div>
<input type="radio" v-model="profileImg" value="p.imgId"> Choose as profile image
</div>
<div><img v-bind:src="BASE_URL +'/uploads/' + userId + '/'+ p.imgId" /> </div>
</div>
</li>
</ul>
The values are otained like this:
created () {
axios.get(this.BASE_URL + '/profile/g/myphotos/', this.jwt)
.then( res => {
this.myPhotos = res.data.photos;
this.showUploadedPhoto = true;
this.profileImg = res.data.profileImg
})
.catch( error => {
console.log(error);
})
},
When an photo is chosen, the profileImg variable should be set to that photo's imgId.
The problem is how to let users to choose only one photo as profile image inside this v-for loop?
Update: a photo my myPhotos object that I'm iterate over:
By providing name you can treat it as one element
var app = new Vue({
el:"#app",
data:{
images:[{imgId:1},{imgId:2},{imgId:3}],
profileImg:2
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>
<div v-for="image in images">
<input type="radio" v-model="profileImg" name="profileImg" :value="image.imgId"> Choose as profile image
</div>
You have selected : {{profileImg}}
</div>
</div>
How about setting name attribute for the input field
<ul v-for="p in myPhotos">
<li>
<div>
<div>
<div>
photo id: {{p.imgId}}
</div>
<input type="radio" name="user_profile_photo" v-model="profileImg" :value="p.imgId"> Choose as profile image
</div>
<div><img v-bind:src="BASE_URL +'/uploads/' + userId + '/'+ p.imgId" /> </div>
</div>
</li>
</ul>

Passing a variable to a Vue component from the parent page that called it

I have a simple table that displays all of my data:
main file.php
<table class="table table-bordered table-hover" id="all-jobs">
<thead>
<tr>
<th>{{ __('Job Name') }}</th>
<th>{{ __('Job Description') }}</th>
<th>{{ __('Job Status') }}</th>
<th>{{ __('Job Applications') }}</th>
<th>{{ __('Manage') }}</th>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td class="non_searchable"></td>
<td class="non_searchable"></td>
</tr>
</thead>
</table>
<div id="app">
<div id="editJob" class="modal fade in" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<edit-job id=""></edit-job>
</div>
</div>
</div>
</div>
Now, I have a edit button that I am trying to open an edit modal for that specific row:
<a href='' data-id='{$job->id}' class='btn btn-xs btn-danger' data-toggle='modal' data-target='#editJob'><i class='fa fa-close'></i></a>";
The href is is location in one of the of my data table, I am trying to pass that to my .vue file so I can use it for my get and post requests:
myfile.vue
<template>
<div>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Edit Job</h4>
</div>
<div class="modal-body">
<form method="post" #submit.prevent="signIn" #keydown="errors.clear($event.target.name)">
<!-- Removed code, it's just inputs !-->
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-info btn-fill btn-wd" v-on:click="addJob">Save</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</template>
<script>
export default
{
props: ['id'],
data: function ()
{
return {
countries: [],
name: '',
summary: '',
salarytype: '',
salaryfrom: '',
salaryto: '',
location: '',
contactemail: '',
contactphone: '',
errors: new Errors()
}
},
methods:
{
addJob: function()
{
axios.post('/jobs/edit', this.$data)
.then(response => {
if(response.data.status === true){
$('#editJob').modal('hide');
getJobTable();
}
else{
formError = response.data.message;
}
})
.catch(error => this.errors.record(error.data))
}
},
mounted: function()
{
console.log($(this).data('id'));
axios.get('/jobs/my-job/')
.then(response => {
this.name = response.data.name
this.summary = response.data.summary
this.salarytype = response.data.salary_type
this.salaryfrom = response.data.salary_from
this.salaryto = response.data.salary_to
this.location = response.data.location
this.contactemail = response.data.contact
this.contactphone = response.data.phone
})
axios.get('/countries')
.then(response => {
this.countries = response.data;
})
}
}
</script>
How can I past my href id to my to use for my request? Thanks
MY structure:
Created-jobs.blade.php
https://pastebin.com/TPBnC1qP
Edit-Job.vue
https://pastebin.com/30UWR5Nn
app.js
https://pastebin.com/1yxZWvVC
The table just populates the data, and adds the dropdown like so:
<ul class='icons-list'>
<li class='dropdown'>
<a href='#' class='dropdown-toggle' data-toggle='dropdown' aria-expanded='false'>
<i class='icon-menu9'></i>
</a>
<ul class='dropdown-menu dropdown-menu-right'>
<li>
<a data-id='{$job->id}' onclick='getID({$job->id})' data-toggle='modal' data-target='#editJob'>
<i class='icon-file-pdf'></i> Edit Job
</a>
</li>
<li>
<a href='javascript:void();' data-id='{$job->id}' onclick='deleteJob({$job->id})'>
<i class='icon-cross'></i> Delete Job
</a>
</li>
</ul>
</li>
</ul>
You don't give a lot of information about the structure of your application, but it looks like you are using at least one single file component to display the data inside your modal which is being entirely displayed via Bootstrap. It also looks like the table with the id values you want to pass to Vue is outside of the Vue itself.
That being the case, the way you can pass the data you want to the single file component is to capture the Vue in a variable and then set the id whenever the link in your table is clicked.
Let's suppose your main.js or app.js looks like this:
import Vue from 'vue'
import EditJob from './EditJob.vue'
Vue.component('edit-job', EditJob)
const app = new Vue({
el: '#app',
data:{
id: null
}
})
// Add a click handler for the links with the `data-id` property.
// This is using jQuery (because you are using Bootstrap) but you
// can do this any way you want.
$("[data-id]").on("click", function(){
// Set the Vue's data to the data-id property in the link.
app.id = this.dataset.id
})
Notice how the code captures the result of new Vue(...) in the variable app. Then I've added the data property, id to the Vue and a click handler for all of your links that sets app.id to this.dataset.id whenever a link is clicked. In this way, every time a link is clicked, the data property in the Vue will be set to the id of the clicked link.
Then, all you need to do is bind the id property to your component.
<edit-job :id="id"></edit-job>
and your EditJob component will always get the updated id.
Here is a working example.
Edit
In the code you added to your example, you are defining all of your jQuery script in Created-jobs.blade.php. That being the case, the function you wrote, getID doesn't have access to the app variable you defined in your webpack bundle because of normal javascript scoping rules. To make app accessible to your jQuery code, add it to the window.
window.app = new Vue({
el: '#app',
data:{
id: null
}
});
Secondly, though you defined the getID function, nothing calls it. It needs to be called when the links are clicked. Add this somewhere to your jQuery code in Created-jobs.blade.php (ideally in a document ready function).
$("[data-id]").on("click", getID)

Vue js v-for v-bind not unique

I'm trying to create a form where I have a select list (fetched from API) and user can add items into a seperate array from this list. New array is also rendered via v-for and uses v-model to edit some additional data.
For example I have a list of goods/services defined beforehand which will be rendered into select option block. Now user can select one of these products and add them to a invoice. After adding (pushed to a new array), user must be able to make some additional changes.
<select class="form-control" v-model="selectedServiceId">
<option v-for="service in services" :value="service._id">{{service.name}}</option>
</select>
<button type="button" class="btn btn-primary" v-on:click="addService">Add</button>
add service method:
addService() {
for (var i = 0; i < this.services.length; i++) {
if (this.services[i]._id == this.selectedServiceId) {
this.services_goods.push(this.services[i])
break;
}
}
}
And now I want to render the list I've pushed into:
<ul>
<li v-for="(item, key) in services_goods">
<span>{{item.name}}</span>
<label for="itemPrice">Price €
<input id="itemPrice" v-model="item.price">
</label>
<label for="itemQty">Quantity
<input type="number" min="1" id="itemQty" v-model="item.quantity">
</label>
<div>
<button type="button" v-on:click="removeService(item._id)">X</button>
</div>
</li>
</ul>
everything is fine up until I add the same item twice and try to modify the price for one of them - it changes price for both.
The reason it changes the price for both is that they are the same object. When you insert an object into an array, the value in the array is a reference to the object. You have two references to the same object.
Each object you insert into the array should be newly created, with contents copied from the selected item.
new Vue({
el: '#app',
data: {
selectedServiceId: null,
services: [{
_id: 1,
price: 1,
quantity: 1,
name: 'First'
},
{
_id: 2,
price: 2,
quantity: 2,
name: 'Second'
}
],
services_goods: []
},
methods: {
addService() {
const foundGood = this.services.find((s) => s._id == this.selectedServiceId);
// Object.assign copies an object's contents
this.services_goods.push(Object.assign({}, foundGood));
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.min.js"></script>
<div id="app">
<select class="form-control" v-model="selectedServiceId">
<option v-for="service in services" :value="service._id">{{service.name}}</option>
</select>
<button type="button" class="btn btn-primary" v-on:click="addService">Add</button>
<ul>
<li v-for="(item, key) in services_goods">
<span>{{item.name}}</span>
<label for="itemPrice">Price €
<input id="itemPrice" v-model="item.price">
</label>
<label for="itemQty">Quantity
<input type="number" min="1" id="itemQty" v-model="item.quantity">
</label>
<div>
<button type="button" v-on:click="removeService(item._id)">X</button>
</div>
</li>
</ul>
</div>