I have data in vue
newContract: {
latest_contract: false,
invoicing_period: "",
}
in computed method I am applying different properties to this.newContract.invoicing_period
computed: {
invoicing_period() {
const period = this.newContract.invoicing_period
const monthToPct = {
1615: "mid_month",
calendarMonth: "calendar_month",
};
return monthToPct[period];
}
}
and in methods I am appending this.invoicing_period from computed
let fd = new FormData();
fd.append("latest_contract", newContract.latest_contract);
fd.append("invoicing_period", this.invoicing_period);
in HTML I have a select dropdown.
<select
id="invoicingDropdown"
name="invoicingPperiod"
v-model="newContract.invoicing_period"
>
<option selected value="1615">15./16.</option>
<option value="calendarMonth">30/31.</option>
</select>
The problem is, that I am sending the correct values after choosing the options from dropdown, but it is not updating the newContract.invoicing_period from vue data().
Thank you.
Related
I have two form fields retrieval-method and source-url, where the later depends on the value of the former. Specifically the text box source-url should be disabled for particular values of retrieval-method. I can achieve this fairly simply as follows:
https://jsfiddle.net/o5mzhg3y/
<div id="app">
<select name="retrieval-method" v-model="retrieval_method">
<option value="">Choose a method</option>
<option value="1">Upload</option>
<option value="2">Download (Periodic)</option>
<option value="3">Download (API Triggered)</option>
</select>
<input type="text" name="source-url" :disabled="!(retrieval_method>1)">
</div>
<script>
new Vue({
el: '#app',
data: {
retrieval_method: false,
source_url: ''
}
})
</script>
However I would like to be able to also reset the fields value to an empty string when the retrieval method changes to something that causes the input to be disabled. But I can't wrap my mind around how to do this. Perhaps I need to implement a method?
Ideally the value would not be forgotten so that if the user changes retrieval-method back to a value that requires a source url the value is reinserted into the text input.
Well you need to do a few things. You can add a watcher to your retrieval_method property. Listen for changes when value changed you save your source_url into a backup field when disable condition is true. And in reverse you read back from your backup filed to your source_url. You should also change your input binding to a v-model binding in order to reflect changes.
new Vue({
el: '#app',
data: {
retrieval_method: false,
source_url: '',
backupUrl: ''
},
computed: {
disableUrl: function() {
return this.retrieval_method <= 1;
}
},
watch: {
// whenever question changes, this function will run
retrieval_method: function(newValue, oldValue) {
if (newValue <= 1) {
this.backupUrl = this.source_url;
this.source_url = '';
} else if (this.backupUrl) {
this.source_url = this.backupUrl;
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.1/vue.js"></script>
<div id="app">
<select name="retrieval-method" v-model="retrieval_method">
<option value="">Choose a method</option>
<option value="1">Upload</option>
<option value="2">Download (Periodic)</option>
<option value="3">Dowload (API Triggered)</option>
</select>
<input type="text" v-model="source_url" :disabled="disableUrl" />
</div>
So I ended up figuring it out by binding a method to the change event
https://jsfiddle.net/o5mzhg3y/7/
<div id="app">
<select name="retrieval-method" v-model="retrieval_method" v-on:change="retrieval_method_changed">
<option value="">Choose a method</option>
<option value="1">Upload</option>
<option value="2">Download (Periodic)</option>
<option value="3">Dowload (API Triggered)</option>
</select>
<input type="text" name="source-url" :disabled="source_disabled" v-model="source_url">
</div>
<script>
new Vue({
el: '#app',
data: {
retrieval_method: '',
source_disabled: true,
source_url: '',
old_source_url: '',
},
methods: {
retrieval_method_changed: function (event) {
const old_source_disabled = this.source_disabled
this.source_disabled = !(this.retrieval_method>1)
if( old_source_disabled != this.source_disabled) {
if(this.source_disabled) {
this.old_source_url = this.source_url
this.source_url = ''
} else {
this.source_url = this.old_source_url
this.old_source_url = ''
}
}
}
}
})
</script>
I'm going to leave the question open though, in case someone comes up with a cleaner way to do what I wanted
I am receiving multiple json files from a server. They are all accessible on different urls based on years (2018,2019 and 2020). I am prefilling these years into a dropdown but now I want to fire a get call with axios everytime I change the value(?year=2018, ?year=2019 or ?year=2020). I also have another dropdown that is prefilled with IDs but have no idea how to attach a certain ID to selected year. These dropdowns are acting as filter for a table that is rendered below.
So to be more clear, when I reload I fire a get call for current year like so: baseurl?year=2019, with this selection I get ALL the data but then if I select an ID, this ID needs to be added to url like so:
baseurl?year=2019?id=0
My current code:
data() {
return {
year:[],
id: 0,
}
},
computed: {
axiosParams(){
const params = new URLSearchParams();
params.append('year', this.year);
return params;
},
//this returns my current year
year() {
var now = new Date()
var nowy = now.getFullYear()
return nowy
},
//this method makes sure that the dropdown is always preffiled
//with following years - eg. next year I only need 2019, 2020 and
//2021
years() {
var yearsArray = []
var now = new Date()
for (let i = -1; i < 2; i++) {
var nowy = now.getFullYear() + i
yearsArray.push(nowy)
}
return yearsArray
},
},
methods: {
getYears: function() {
axios.get('myurl',{
params : this.axiosParams
}
}).then((response) => {
this.year = response.data;
this.table = response.data;
})
},
getId: function() {
axios.get('myurl',{
params : {
year: this.year,
id : this.id
}
}
}).then((response) => {
this.id = response.data;
this.table = response.data;
})
},
},
created: {
this.getYears();
this.getId();
}
My HTML:
<select v-model="year">
<option v-model="yearsArray" v-for="year in years">{{year}} .
</option></select>
<select v-model="id"><option v-for="item in id">{{item}}</option> .
</select>
Thanks!
So, if I understand, you want to trigger an axios call when an id is selected. This can be done a couple of ways but this way will trigger on the selection of an id, and also on the selection of a year.
<select v-model="selectedYear" #change="yearSelected">
<option v-for="year in years" :key="year" :value="year">{{year}} .</option>
</select>
<select v-model="selectedId" #change="idSelected">
<option v-for="id in ids" :key="id" :value="id">{{id}}</option> .
</select>
Here, the years is from your computed property for years and ids is what you said was a dropdown "prefilled with IDs". The two v-model properties are initially set to null then are assigned a value on selection. They are defined in data like so.
data: () => ({
selectedId: null,
selectedYear: null,
}),
Each has a function call to do something with the selected option, #change="idSelected" which calls this method:
methods: {
idSelected() {
console.log(this.selectedId)
// here you make you axios call using this.selectedId as the param
axios.get('myurl',{
params : {
year: this.selectedYear,
id : this.selectedId
}
},
...
}
You could have the two selects without the #change and have a button that triggers the function call with #click. Either way you use the selectedId and selectedYear in that method.
SAMPLE https://stackblitz.com/edit/usjgwp?file=index.html
I want to show a number of kendo dropdownlist(s) on a page. The exact number depends on an API call. This API call will give me an array of stakeholder objects. Stakeholder objects have the following properties: Id, name, type, role and isSelected.
The number of dropdownlist that has to be shown on this page should be equal to the number of unique type values in the API response array. i.e,
numberOfDropdowns = stakeholders.map(a => a.type).distinct().count().
Now, each dropdown will have a datasource based on the type property. i.e, For a dropdown for type = 1, dataSource will be stakeholders.filter(s => s.type == 1).
Also the default values in the dropdowns will be based on the isSelected property. For every type, only one object will have isSelected = true.
I have achieved these things by using the following code:
<template>
<div
v-if="selectedStakeholders.length > 0"
v-for="(stakeholderLabel, index) in stakeholderLabels"
:key="stakeholderLabel.Key"
>
<label>{{ stakeholderLabel.Value }}:</label>
<kendo-dropdownlist
v-model="selectedStakeholders[index].Id"
:data-source="stakeholders.filter(s => s.type == stakeholderLabel.Key)"
data-text-field="name"
data-value-field="Id"
></kendo-dropdownlist>
<button #click="updateStakeholders">Update form</button>
</div>
</template>
<script>
import STAKEHOLDER_SERVICE from "somePath";
export default {
name: "someName",
props: {
value1: String,
value2: String,
},
data() {
return {
payload: {
value1: this.value1,
value2: this.value2
},
stakeholders: [],
selectedStakeholders: [],
stakeholderLabels: [] // [{Key: 1, Value: "Stakeholder1"}, {Key: 2, Value: "Stakeholder2"}, ... ]
};
},
mounted: async function() {
await this.setStakeholderLabels();
await this.setStakeholderDataSource();
this.setSelectedStakeholdersArray();
},
methods: {
async setStakeholderLabels() {
let kvPairs = await STAKEHOLDER_SERVICE.getStakeholderLabels();
kvPairs = kvPairs.sort((kv1, kv2) => (kv1.Key > kv2.Key ? 1 : -1));
kvPairs.forEach(kvPair => this.stakeholderLabels.push(kvPair));
},
async setStakeholderDataSource() {
this.stakeholders = await STAKEHOLDER_SERVICE.getStakeholders(
this.payload
);
}
setSelectedStakeholdersArray() {
const selectedStakeholders = this.stakeholders
.filter(s => s.isSelected === true)
.sort((s1, s2) => (s1.type > s2.type ? 1 : -1));
selectedStakeholders.forEach(selectedStakeholder =>
this.selectedStakeholders.push(selectedStakeholder)
);
},
async updateStakeholders() {
console.log(this.selectedStakeholders);
}
}
};
</script>
The problem is that I am not able to change the selection in the dropdownlist the selection always remains the same as the default selected values. Even when I choose a different option in any dropdownlist, the selection does not actually change.
I've also tried binding like this:
<kendo-dropdownlist
v-model="selectedStakeholders[index]"
value-primitive="false"
:data-source="stakeholders.filter(s => s.type == stakeholderLabel.Key)"
data-text-field="name"
data-value-field="Id"
></kendo-dropdownlist>
If I bind like this, I am able to change selection but then the default selection does not happen, the first option is always the selection option i.e, default selection is not based on the isSelected property.
My requirement is that I have to show the dropdown with some default selections, allow the user to choose different options in all the different dropdowns and then retrieve all the selection then the update button is clicked.
UPDATE:
When I use the first method for binding, The Id property of objects in the selectedStakeholders array is actually changing, but it does not reflect on the UI, i.e, on the UI, the selected option is always the default option even when user changes selection.
Also when I subscribe to the change and select events, I see that only select event is being triggered, change event never triggers.
So it turns out that it was a Vue.js limitation (or a JS limitation which vue inherited),
Link
I had to explicitly change the values in selectedStakeholders array like this:
<template>
<div
v-if="selectedStakeholders.length > 0"
v-for="(stakeholderLabel, index) in stakeholderLabels"
:key="stakeholderLabel.Key"
>
<label>{{ stakeholderLabel.Value }}:</label>
<kendo-dropdownlist
v-model="selectedStakeholders[index].Id"
:data-source="stakeholders.filter(s => s.type == stakeholderLabel.Key)"
data-text-field="name"
data-value-field="Id"
#select="selected"
></kendo-dropdownlist>
<button #click="updateStakeholders">Update form</button>
</div>
</template>
And in methods:
selected(e) {
const stakeholderTypeId = e.dataItem.type;
const selectedStakeholderIndexForTypeId = this.selectedStakeholders.findIndex(
s => s.type == stakeholderTypeId
);
this.$set(
this.selectedStakeholders,
selectedStakeholderIndexForTypeId,
e.dataItem
);
}
I want to change the second select list according to the selected value in the first one. It worked when i did two Vue instances for each select, but i wanted to do a small app so its all a bit cleaner.
The types JSON array needs to be outside the Vue JS. You can see it in the fiddle.
Somehow i just dont get how to update the second selectlist.
Before i did something like this and it worked perfectly:
// methods of first select (category)
methods: {
update: function (value)
this.options = types[value]
}
}
...
// methods of second select (typselect)
methods: {
onChange(event) {
typselect.update(event.srcElement.value)
}
}
The app:
<div id="app">
<select v-model="category" v-on:change="onChange">
<option>Choose</option>
<option value="5">type1</option>
<option value="6">type2</option>
<option value="11">type3</option>
</select>
<select id="typselect">
<option v-for="option in options" v-bind:value="option.value">{{ option.text }}</option>
</select>
</div>
So i switched that for something like this:
new Vue({
el: '#app',
data: {
category: '5'
},
computed: {
options: function(event) {
console.log('should be called on change');
let options = ''
options = 1;
// options = types[event.srcElement.value]; // this would be so easy...
return options
}
},
methods: {
onChange: function(e) {
console.log(event.srcElement.value);
this.options = this.options
}
}
})
But i just don't get how to get the second selectlist updated.
Here come a fiddle:
https://jsfiddle.net/Honkoman/g9g5uukr/2/
Your computed should look like this.
computed: {
options: function(event) {
return types[this.category]
}
},
Updated fiddle.
i'm really new to AngularJS and i like it very much.
But i'm experiencing a problem trying to initialize a prealoaded dropdown with a specific value.
The dropdown is initialized with values available from JSON array, but when i try to select a default value in this dropdown, i don't see that value selected but the ng-model variable is set correctly.
I created a plunker example here http://plnkr.co/edit/7su3Etr1JNYEz324CMy7?p=preview tryng to achieve what i want, but i can't get it to work. I tried with ng-repeat and ng-select, with no luck. Another try i did (in this example) is trying to set the ng-selected property.
This is a part of my html
<body ng-controller="MySampleController">
<select name="repeatSelect" id="repeatSelect" ng-model="SelectedStatus" ng-init="SelectedStatus">
<option ng-repeat="option in StatusList[0]" value="{{option.key}}" ng-selected="{{option.key==SelectedStatus}}">{{option.name}}</option>
</select>
<select name="repeatSelect" id="repeatSelect" ng-model="SelectedOrigin">
<option ng-repeat="option in OriginList[0]" value="{{option.key}}" ng-selected="{{option.key == SelectedOrigin}}">{{option.key}} - {{option.name}}</option>
</select>
<pre>Selected Value For Status: {{SelectedStatus}}</pre>
<pre>{{StatusList[0]}}</pre>
<pre>Selected Value For Origin: {{SelectedOrigin}}</pre>
<pre>{{OriginList[0]}}</pre>
</body>
And this is code from my controller
function MySampleController($scope) {
$scope.StatusList = [];
$scope.OriginList = [];
$scope.ServiceCall = {};
$scope.EntityList = [];
$scope.SelectedStatus = -3;
$scope.SelectedOrigin = 1;
var myList = [
{
item: 'Status',
values: [{ key: -3, name: 'Aperto' },
{ key: -1, name: 'Chiuso' }]
},
{
item: 'Origin',
values: [{ key: 1, name: 'Origin1' },
{ key: 2, name: 'Origin2' },
{ key: 3, name: 'Origin3' }]
}
];
$scope.documentsData = myList;
angular.forEach($scope.documentsData, function (value) {
$scope.EntityList.push(value);
switch ($scope.EntityList[0].item) {
case 'Status':
$scope.StatusList.push($scope.EntityList[0].values);
$scope.EntityList = [];
break;
case 'Origin':
$scope.OriginList.push($scope.EntityList[0].values);
$scope.EntityList = [];
break;
}
});
}
Any help would be appreciated!
Thanks in advance.
You can at least use ng-options instead of ng-repeat + option, in which case the default value works just fine.
<select name="repeatSelect" id="repeatSelect"
ng-options="opt.key as opt.key+'-'+opt.name for opt in StatusList[0]"
ng-model="SelectedStatus"></select>`
You can also make it a bit more readable by specifying the option label as a scope function.
HTML: ng-options="opt.key as getOptionLabel(opt) for opt in StatusList[0]"
Controller:
$scope.getOptionLabel = function(option) {
return option.key + " - " + option.name;
}
Plunker: http://plnkr.co/edit/7BcAuzX5JV7lCQh772oo?p=preview
Value of a select directive used without ngOptions is always a string.
Set as following and it would work
$scope.SelectedStatus = '-3';
$scope.SelectedOrigin = '1';
Read answer here in details ng-selected does not work with ng-repeat to set default value