How to get an id of value in Vue.js - javascript

I am getting the data from API and I'm stuck with getting an id in order to send it back.
Example of data from API:
{
id:1,
name: 'qwerty',
},
{
id:2,
name: 'ytrewq',
},
API endpoint is expecting sending id via axios.post, not value, but v-model gets exactly the value.
<div class="form-group col-md-9">
<select class="form-select" id="inputSubject" v-model='subject'>
<option disabled value="">Select subject</option>
<option v-for="item in subjects" v-bind:value="item.name" :key="item.id">{{ item.name }}</option>
</select>
</div>
<div class="form-group col-md-9">
<select class="form-select" id="inputWorkType" v-model='work_type'>
<option disabled value="">Select work type</option>
<option v-for="item in work_types" v-bind:value="item.name" :key="item.id">{{item.name}}</option>
</select>
</div>
<script>
export default {
data () {
return {
subject: '',
work_type: '',
subjects: [],
work_types: [],
}
},
methods: {
// getting the data
getSubjectsWorkTypes() {
axios
.all([axios.get('/api/v1/subjects/'),
axios.get('/api/v1/worktypes/')
])
.then (
axios.spread((firstResponse, secondResponse) => {
console.log(firstResponse.data)
console.log(secondResponse.data)
this.subjects = firstResponse.data
this.work_types = secondResponse.data
}))
},
// sending the data
submitForm() {
console.log(this.subject.key())
const formData = {
subject: this.subject,
work_type: this.work_type,
}
axios
.post("api/v1/orders/", formData)
},
}
</script>
is there any smart way to get and send id? the only idea I have is to build the function which filters an array into finding id for the selected string...

the value of <select> is the selected <option>s value
You've set the value of the option to be the .name instead of the .id
const { ref, createApp, onMounted } = Vue;
createApp({
setup() {
const subject = ref("");
const subjects = ref([]);
const work_type = ref("");
const work_types = ref([]);
onMounted(() => {
// simulate API load
setTimeout(() => {
subjects.value = [
{ id: 1, name: 'qwerty', },
{ id: 2, name: 'ytrewq', },
];
work_types.value = [
{ id: 1, name: 'qwerty', },
{ id: 2, name: 'ytrewq', },
];
}, 1000);
});
return { subject, subjects, work_type, work_types, };
}
}).mount('#app');
#app {
display:flex;
justify-content: center;
gap:2rem;
}
.contain {
width:14rem;
}
.disp {
margin-bottom: 1rem;
}
.as-console-wrapper { max-height: 0 !important}
<script src="https://unpkg.com/vue#next"></script>
<div id="app">
<div class="contain">
This is wrong
<div class="disp">
Selected ID is {{ subject }}
</div>
<div>
<select class="form-select" id="inputSubject" v-model='subject'>
<option disabled value="">Select Work Type</option>
<option
v-for="item in subjects"
v-bind:value="item.name"
:key="item.id"
>
{{ item.name }}
</option>
</select>
</div>
</div>
<div class="contain">
This is right
<div class="disp">
Selected ID is {{ work_type }}
</div>
<div>
<select class="form-select" id="inputSubject" v-model='work_type'>
<option disabled value="">Select subject</option>
<option
v-for="item in work_types"
v-bind:value="item.id"
:key="item.id"
>
{{ item.name }}
</option>
</select>
</div>
</div>
</div>

Related

How to sum selected values in option tag

So I have a v-for loop and 7 different documents from mongo database. Every document contains one food and for each food it has specific number of calories. And I want to sum all the selected calories. For example I got a variable food.calorie_number. Okay so I have something like this:
<tr>
<td v-for="(food) in fetch_breakfast.slice(8,15)" :key=food.id>Meal <p style="border-top: 3px solid #dddddd;">
<select class="form-select" aria-label="Default select example">
<option selected>Select your food</option>
<option v-bind:value="food.id">{{food.food}}</option>
<!-- Every meal has food.calorie_number -->
<option value="3"></option>
</select>
</p></td>
<p>Calorie sum: {{Sum}}</p>
</tr>
I wanted to do something like this: Sum = Sum + food.calorie_number but i didn't get the final solution because I don't know how to do it for a specific element generated by v-for.
If I understood you correctly try like following snippet (with computed and method for selection) :
new Vue({
el: '#demo',
data() {
return {
fetch_breakfast: [{id: 1, food: 'apple', calorie_number: 80}, {id: 2, food: 'peach', calorie_number: 70}, {id: 3, food: 'carrot', calorie_number: 90}],
selected: []
}
},
computed: {
sum() {
return this.selected.reduce((acc, curr) => acc + curr.calorie_number, 0)
}
},
methods: {
getSum(food) {
const idx = this.selected.findIndex(s => s.id === food.id)
idx > -1 ? this.selected.splice(idx, 1) : this.selected.push(food)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<table>
<tr>
<td v-for="food in fetch_breakfast" :key=food.id>Meal
<p>
<select class="form-select" #change="getSum(food)">
<option selected>Select your food</option>
<option :value="food.id">{{ food.food }}</option>
</select>
</p>
</td>
<p>Calorie sum: {{ sum }}</p>
</tr>
</table>
</div>
First you have v-for on the wrong element because that way it will return 7 select. if you want to have seven options put v-for in select but to have a default option that is not affected by the loop put in option like this:
then do your logic and fetch in either computed value
var selector = new Vue({
el: '#selector',
data: {
selected: null,
meals: [
{'id':1,
"name":"food_name_1",
"calories":"1.6g"
},
{'id':2,
"name":"food_name_g",
"calories":"1.8g"
},
{'id':3,
"name":"food_name_v",
"calories":"1.9g"
},
{'id':9,
"name":"food_name_v",
"calories":"1.66g"
},
{'id':11,
"name":"food_name_y",
"calories":"1.1g"
},
]
},
computed:{
selected_food(){
let id = this.selected
let selected_meal = this.meals.find(meal => meal.id === id)
return selected_meal
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="selector">
<select :default="0" v-model="selected">
<option selected="selected" :value=null>select meal</option>
<option v-for="(meal, key) in meals" :key=key :value="meal.id">
{{ meal.name }}
</option>
</select>
<br>
<br>
<div v-if="selected">
<span > Selected food : {{selected_food.name}}</span> </br>
<span > Selected food Calory : {{selected_food.calories}}</span>
</div>
<span v-else>Please select a meal</span>
</div>

Hide specific options in second and third select menus based on previous selections in VueJS

I would like to show/hide certain options in select menu 2 depending on what is chosen in select 1 and also show/hide certain options in select menu 3 depending on what is chosen in select menu 2.
For example, if the user selects 'Subject01' in the first menu I would like to hide 'Subject04' and 'Subject08' in menu 2. If the user selects 'Subject016' in select 2, I would like to hide 'Subject11' in menu 3. I have several scenarios based on the subject selections. So these are just examples.
I can add a class to the but I don't know how to add to the individual tags.
Any help appreciated.
The code:
<template>
<select v-model="one" id="selectone">
<option v-for="subject in subjects" :key="subject">
{{ subject }}
</option>
</select>
<select v-model="two" :disabled="!one" id="selecttwo">
<option
v-for="subject in subjects.filter((item) =>
item.split(' ')[0].indexOf(this.one.split(' ')[0])
)"
:key="subject"
>
{{ subject }}
</option>
</select>
<select v-model="three" :disabled="!two" id="selectthree">
<option
v-for="subject in subjects.filter(
(item) =>
item.split(' ')[0].indexOf(this.one.split(' ')[0]) &&
item.split(' ')[0].indexOf(this.two.split(' ')[0])
)"
:key="subject"
>
{{ subject }}
</option>
</select>
<div v-if="one">You have selected: {{ one }} {{ two }} {{ three }}</div>
</template>
<script>
export default {
data() {
return {
subjects: [
"Subject01",
"Subject02",
"Subject03",
"Subject04",
"Subject05",
"Subject06",
"Subject07",
"Subject08",
"Subject09",
"Subject10",
"Subject11",
"Subject12",
"Subject13",
"Subject14",
"Subject15",
"Subject16",
],
one: "",
two: "",
three: "",
};
},
methods: {},
};
</script>
<style>
li {
list-style-type: none;
}
.hide {
display: none;
}
.show {
display: block;
}
</style>
You can create objects in data property with matching cases for showing items and then use computed properties:
new Vue({
el: "#demo",
data() {
return {
subjects: ["Subject01", "Subject02", "Subject03", "Subject04", "Subject05", "Subject06", "Subject07", "Subject08", "Subject09", "Subject10", "Subject11", "Subject12", "Subject13", "Subject14", "Subject15", "Subject16",],
disOne: {"Subject01":["Subject04", "Subject08"]}, // you can set here other cases for example for some other subject dont show array of other subjects
disTwo: {"Subject16":["Subject11"]},
one: "",
two: "",
three: "",
}
},
computed: {
sub2() {
if (this.one) {
return this.subjects.filter(s => !this.disOne[this.one].includes(s))
}
},
sub3() {
if (this.two) {
return this.subjects.filter(s => !this.disTwo[this.two].includes(s))
}
}
},
methods: {},
})
li {
list-style-type: none;
}
.hide {
display: none;
}
.show {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<select v-model="one" id="selectone">
<option v-for="subject in subjects" :key="subject">
{{ subject }}
</option>
</select>
<select v-model="two" :disabled="!one" id="selecttwo">
<option
v-for="subject in sub2"
:key="subject"
>
{{ subject }}
</option>
</select>
<select v-model="three" :disabled="!two" id="selectthree">
<option
v-for="subject in sub3"
:key="subject"
>
{{ subject }}
</option>
</select>
<div v-if="one">You have selected: {{ one }} {{ two }} {{ three }}</div>
</div>
As #wittgenstein said, you can use a computed property:
new Vue({
el: '#app',
data() {
return {
subjects: [
"Subject01",
"Subject02",
"Subject03",
"Subject04",
"Subject05",
"Subject06",
"Subject07",
"Subject08",
"Subject09",
"Subject10",
"Subject11",
"Subject12",
"Subject13",
"Subject14",
"Subject15",
"Subject16",
],
one: "",
two: "",
three: "",
};
},
computed: {
select1() {
return this.subjects
},
select2() {
if (this.one === 'Subject01') {
return this.subjects.filter(subject => !['Subject04', 'Subject08'].includes(subject))
}
return this.subjects
},
select3() {
if (this.two === 'Subject16') {
return this.subjects.filter(subject => subject !== 'Subject04')
}
return this.subjects
},
},
methods: {},
});
li {
list-style-type: none;
}
.hide {
display: none;
}
.show {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<select v-model="one" id="selectone">
<option v-for="subject in select1" :key="subject">
{{ subject }}
</option>
</select>
<select v-model="two" :disabled="!one" id="selecttwo">
<option
v-for="subject in select2"
:key="subject"
>
{{ subject }}
</option>
</select>
<select v-model="three" :disabled="!two" id="selectthree">
<option
v-for="subject in select3"
:key="subject"
>
{{ subject }}
</option>
</select>
<div v-if="one">You have selected: {{ one }} {{ two }} {{ three }}</div>
</div>
Have separate computer properties as source for 2nd and 3rd select options and render them in loops.
When first select option value changes, these computer properties will automatically update.
Make sure you use :key else order of rendering options may be inconsistent.

Element deleted from the array but v-for doesn't update VUEJS

Guys so I'm trying to develop this rule component which can be spawned by my main component as many times as he wants but the problem is that when I delete an index from the list that tracks the number of rules, the vuejs layout doesn't update accordingly. What I mean by this is that if I check the array it self it deleted the correct item but when I look at the vue page (HTML) it either doesn't delete anything or only deletes the last item, and this may be caused by the v-for not updating on list change but I don't know how to solve this.
NewTask.vue (Parent)
<template>
<div class="mt-4">
<div class="container">
<div class="if-condition container-fluid d-flex flex-row ps-0">
<span class="text-center me-2 condition rounded">IF</span>
<select class="form-select form-select-sm me-2 if-select" v-model="if_condition">
<option value="ALL">ALL</option>
<option value="ANY">ANY</option>
<option value="NONE">NONE</option>
</select>
<span>of these filters match</span>
</div>
<div class="mt-2 ps-3 pt-3 pb-3 border">
<new-rule v-for="(item, index) in rules"
:key="JSON.stringify(index)" v-on:remove-rule="removeRule(index)"
:data="item" :index="index" v-on:data-changed="dataChanged"
class="mb-2"/>
<div class="mt-2 add-rule-div">
<button class="btn add-rule-btn" v-on:click="addRule">+</button>
</div>
</div>
</div>
</div>
</template>
<script>
import Rule from '#/components/rule'
export default {
name: "NewTask",
components: {
'new-rule': Rule
},
data: function () {
return {
if_condition: 'ALL',
rules: []
}
},
methods: {
dataChanged(data) {
const rules = this.rules;
const index = data.index;
delete data['index'];
rules.splice(index, 1, data)
this.rules = rules;
},
removeRule(index) {
const rules = this.rules;
rules.splice(index, 1)
this.rules = rules
},
addRule() {
const new_rule = {
type_input_text: null,
type_input_show: null,
rule_input_text: null,
rule_input_show: null,
}
this.rules.push(new_rule)
console.log(this.rules)
}
}
}
</script>
rule.vue (Child)
<template>
<div class="if-condition d-flex flex-row">
<select class="form-select form-select-sm me-2"
v-on:change="checkTypeSelect" v-model="type_select">
<option value="HTML">HTML</option>
<option value="XPATH">XPATH</option>
<option value="ID">ID</option>
<option value="CLASS">CLASS</option>
</select>
<input v-if="type_input_show" type="text" class="form-control me-2" v-model="type_input_text" v-on:change="dataChanged">
<select class="form-select form-select-sm me-2"
v-on:change="checkRuleSelect" v-model="rule_select">
<option value="CONTAINS">CONTAINS</option>
<option value="EXISTS">EXISTS</option>
</select>
<input v-if="rule_input_show" type="text" class="form-control me-2" v-model="rule_input_text" v-on:change="dataChanged">
<button class="btn remove-rule-btn pb-0 pt-0 ps-2 pe-2" v-on:click="this.$emit('remove-rule')">-</button>
</div>
</template>
<script>
export default {
name: "rule",
props: {
data: {
type: Object,
required: true
},
index: {
type: Number,
required: true
}
},
data: function () {
return {
type_select: 'HTML',
type_input_text: '',
rule_select: 'CONTAINS',
rule_input_text: '',
//
type_input_show: false,
rule_input_show: true,
}
},
beforeMount() {
if (this.data.type_select) {
this.type_select = this.data.type_select
this.checkTypeSelect()
}
if (this.data.type_input_text) {
this.type_input_text = this.data.type_input_text
}
if (this.data.rule_select) {
this.rule_select = this.data.rule_select
this.checkRuleSelect()
}
if (this.data.rule_input_text) {
this.rule_input_text = this.data.rule_input_text
}
},
methods: {
dataChanged() {
const new_data = {
index: this.index,
type_select: this.type_select,
type_input_text: this.type_input_text,
rule_select: this.rule_select,
rule_input_text: this.rule_input_text
}
this.$emit('data-changed', new_data)
},
checkTypeSelect() {
const type_select = this.type_select;
this.type_input_show = type_select !== 'HTML';
this.dataChanged()
},
checkRuleSelect() {
const rule_select = this.rule_select;
this.rule_input_show = rule_select !== 'EXISTS';
this.dataChanged()
}
}
}
</script>
Some images to demonstrate the issue:
Array Before Index delete:
Array After Index delete:
For further investigation feel free to visit the repo: https://github.com/DEADSEC-SECURITY/Easy-Scraper
THIS IS NOT PUBLICITY, I TRULY NEED HELP
You are using the index as a key. VueJS updates the DOM based on the change in key. So you have two options:
Use some distinct data from each entry or combination as a key.
Provide no key because as per Vuejs docs you need not provide a key anymore.

Angular 2 changing disabled/enabled select options

I'm using Angular2 and I have 2 selects:
<div ng-controller="ExampleController">
<form name="myForm">
<label for="companySelect"> Company: </label>
<select name="companySelect" id="companySelect">
<option *ngFor="let company of companies"
value="{{company.id}}"> {{company.name}}
</option>
</select>
<label for="documentTypeSelect"> Type: </label>
<select name="documentTypeSelect" id="documentTypeSelect">
<option value="type1">type1</option>
<option value="type2">type2</option>
<option value="type3">type3</option>
</select>
</form>
<hr>
</div>
I want to change second select options depending on the first select. I can get types (boolean value) by using
company.companyRelations.pop().type1
company.companyRelations.pop().type2
And now, if for example type1 is false, the option in second select should be disabled and if type2 is true, option should be enabled. Is that possible?
EDIT:
Companies in select have deasdv, invoic and orders properties which are true or false. How can i now pass these properties into component.ts properties? Is it possible by event or what? I want to get for example
company.companyRelations.pop().desadv
For company which is selected and it will change disabled options in the second one.
html
<form name="myForm">
<label for="companySelect"> Company: </label>
<select class="form-control" name="companySelect" id="companySelect"
[(ngModel)]="companySelect" (ngModelChange)="onChange($event)">
<option [ngValue]="undefined" disabled selected>Select...</option>
<option *ngFor="let company of companies" [ngValue]="company.id">
{{company.name}}</option>
</select>
<select name="documentTypeSelect" id="documentTypeSelect">
<option [ngValue]="undefined" disabled selected>Select...</option>
<option [disabled]="!desadv" value="desadv">desadv</option>
<option [disabled]="!invoic" value="invoic">invoic</option>
<option [disabled]="!orders" value="orders">orders</option>
</select>
</form>
component.ts
desadv: boolean = false;
invoic: boolean = false;
orders: boolean = false;
and here it will be something like:
onChange(event) {
if(event.desadv) {
this.desadv = true;
}
}
My solution:
html
<form name="myForm">
<label for="companySelect"> Company: </label>
<select name="companySelect" id="companySelect" [(ngModel)]="companySelect"
(ngModelChange)="onChange($event)">
<option [ngValue]="undefined" disabled selected>Select...</option>
<option *ngFor="let company of companies" [ngValue]="company">
{{company.name}}</option>
</select>
<label for="documentTypeSelect"> Type: </label>
<select name="documentTypeSelect" id="documentTypeSelect">
<option [ngValue]="undefined" disabled selected>Select...</option>
<option [disabled]="!desadv" value="desadv">desadv</option>
<option [disabled]="!invoic" value="invoic">invoic</option>
<option [disabled]="!orders" value="orders">orders</option>
<option [disabled]="!recadv" value="orders">recadv</option>
<option [disabled]="!shipment" value="orders">shipment</option>
</select>
component.ts
onChange(event) {
this.desadv = event.companyRelations[0].desadv;
this.invoic = event.companyRelations[0].invoic;
this.orders = event.companyRelations[0].orders;
this.recadv = event.companyRelations[0].recadv;
this.shipment = event.companyRelations[0].shipment;
}
Try this :
<select class="form-control" name="companySelect" id="companySelect" [(ngModel)]="companySelect" (ngModelChange)="onChange($event)">
<option [ngValue]="undefined" disabled selected>Select...</option>
<option *ngFor="let company of companies" [ngValue]="company.id">{{company.name}}</option>
</select>
<select [disabled]="btnDisable" name="documentTypeSelect" id="documentTypeSelect">
<option value="type1">type1</option>
<option value="type2">type2</option>
<option value="type3">type3</option>
</select>
component.ts
private companySelect: any;
private btnDisable: boolean = true;
onChange(event) {
if(event) {
this.btnDisable = false;
}
}
Yes it is possible.
I have created a demo in which second drop down will be enabled depending upon the value of flag in first drop down object.
// Code goes here
var myApp = angular.module('plunker',[]);
angular.module('plunker').controller('MyCtrl', MyCtrl)
MyCtrl.$inject = ['$scope'];
function MyCtrl($scope) {
$scope.items1 = [{
id: 1,
label: 'aLabel',
'flag':true,
subItem: { name: 'aSubItem' }
}, {
id: 2,
label: 'bLabel',
'flag':false,
subItem: { name: 'bSubItem' }
}];
$scope.items2 = [{
id: 1,
label: 'MyName',
'flag':true,
subItem: { name: 'aSubItem' }
}, {
id: 2,
label: 'YourName',
'flag':false,
subItem: { name: 'bSubItem' }
}];
$scope.changeDetect = function(){
$scope.selected1='';
console.log($scope.selected);
if($scope.selected.flag)
{
$scope.flagValue=false;
} else {
$scope.flagValue=true;
}
}
$scope.flagValue=true;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.min.js"></script>
<div ng-app="plunker" ng-controller="MyCtrl">
<select ng-options="item as item.label for item in items1 track by item.id" ng-model="selected" ng-change="changeDetect()"></select>
<select ng-options="item as item.label for item in items2 track by item.id" ng-model="selected1" ng-disabled="flagValue"></select>
</div>
In AngularJS 2
<select [ngModel]="selectedDeviceObj" (ngModelChange)="onChangeObj($event)" name="sel3">
<option [ngValue]="i" *ngFor="let i of deviceObjects">{{i.name}}</option>
</select>
<select [ngModel]="selectedDeviceObj1" name="sel2" [disabled]="flag">
<option [ngValue]="i" *ngFor="let i of deviceObjects1">{{i.name}}</option>
</select>
onChangeObj(newObj) {
this.selectedDeviceObj1='';
console.log(newObj);
this.selectedDeviceObj = newObj;
if(newObj.flag){
this.flag = false;
}
else {
this.flag = true;
}
Please find Demo Link Plunkr

Retrieve selected text from select

I'm using VueJS 2 (with this template) and below is what I've done so far:
<template>
<select id="dropDown" v-model="mytrack">
<option value="">Select track</option>
<option v-for="track in tracksList" :value="track.circuitId">{{ track.name }}</option>
</select>
<button type="submit" #click="retrieveByTrack(track.circuitId)">
Search
</button>
</template>
<script>
export default {
data() {
return {
tracksList: []
};
},
created: {
// here I fill tracksList[] with a list of tracks
},
methods: {
retrieveByTrack(trackId){
}
}
}
</script>
I want to be able to select an option from the select element and when I click the submit button I should call retrieveByTrack(track.circuitId) method passing the option value selected in the select element.
Simple like that.
I created fiddle for you:
https://jsfiddle.net/npw7fgta/
<div class='col-xs-12'>
<hr/>
<div id="app">
<pre>{{ $data |json }}</pre>
<select v-model='result'> <option v-for="task in tasks" :value="task.id">{{ task.name }} </option> </select>
</div>
</div>
And JS:
var vm = new Vue({
el: "#app",
data: {
tasks: [
{ id: 0 , name: 'First task'},
{ id: 5, name: 'fifth task'}
]
}
});
Then you have task/track.id available in result so you can do whatever you want.

Categories

Resources