I want to watch kendo multiselect value change with angular $watch, but it does not work.
Is there something wrong in my code. How can I fix it?
code as follows (or jsbin)
The value A change stop watch after first invoke.
<body ng-app="myapp">
<div ng-controller="mycontroller">
ValueA :{{ ValueA }} , Change count: {{ valueAChangeCnt }}<br />
<div multiple="multiple"
kendo-multi-select
data-placeholder="Select attendees..."
k-data-text-field = "'name'",
k-data-value-field = "'index'",
k-data-source='dsA'
ng-model='ValueA'
>
</div>
<br />
<br />
ValueB :{{ ValueB }} , Change count: {{ valueBChangeCnt }}<br />
<br />
<select ng-model="ValueB">
<option value="1">A</option>
<option value="2">B</option>
<option value="3">C</option>
<option value="4">D</option>
<option value="5">E</option>
<option value="6">F</option>
</select>
</div>
</body>
<script type="text/javascript">
var MyApp = angular.module('myapp', ['kendo.directives']);
function mycontroller($scope) {
$scope.dsA = new kendo.data.DataSource({
data: [
{ name: "A", index: 1 },
{ name: "B", index: 2 },
{ name: "C", index: 3 },
{ name: "D", index: 4 },
{ name: "E", index: 5 },
{ name: "F", index: 6 }
]
});
$scope.valueAChangeCnt = 0;
$scope.$watch('ValueA', function() {
console.log('ValueA Changed');
$scope.valueAChangeCnt++;
});
$scope.valueBChangeCnt = 0;
$scope.$watch('ValueB', function() {
console.log('ValueB Changed');
$scope.valueBChangeCnt++;
});
}
mycontroller.$inject = ['$scope'];
</script>
Insert true after $watch listener function:
$scope.$watch('ValueA', function() {
console.log('ValueA Changed');
$scope.valueAChangeCnt++;
}, true);
This will compare object for equality rather than for reference. From AngularJS API
Related
I have two drop-down menus. Depending on the choice of the first drop-down the choices of the second need to be filtered and displayed. The first dropdown has a RoomID value that is used to filter an array of objects for the second drop-down menu. When I select a Room in the first dropdown the console log shows the correct data for the second dropdown. however, it is not rendering in the Html. I am not sure why this is not working
Html:
<div id="reports-menu" class="myTextColor1 pl-10">
<div class="row">
<div class="input-field col s12">
<select v-model="selectedRoomID">
<option disabled selected>Rooms</option>
<option v-for="room in rooms" v-bind:value="room.RoomID">{{room.Room}}</option>
</select>
<label>Room:</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<select v-model="selectedTopicID">
<option disabled selected>Topics</option>
<option v-for="option in selectedRoom" v-bind:value="option.TopicID">{{option.Topic}}</option>
</select>
<label>Topic:</label>
</div>
</div>
</div>
JS:
var data = <%=return_message%>;
let arrRooms = _.uniqBy(data, function (e) {
return e.Room;
});
let arrTopics = _.uniqBy(data, function (e) {
return e.Topic;
});
let arrDps = _.uniqBy(data, function (e) {
return e.DiscussionPoint;
});
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('select');
var instances = M.FormSelect.init(elems, {});
});
var chatReportsMenuComponent = new Vue({
el: "#reports-menu",
created: function () {
document.getElementById("reports-menu").style.display = "block";
//GET TOPIC INFO - PASS TOPIC PARAM;
this.initialize();
},
data: {
selectedRoomID: undefined,
rooms:arrRooms,
selectedTopicID: undefined,
topics:arrTopics,
dps:arrDps
},
methods: {
initialize: function () {
var self = this;
}
},
computed:{
selectedRoom: function(){
var filteredTopics = _.filter(arrTopics,{'RoomID': this.selectedRoomID})
console.log("Filterd Topics: ", filteredTopics)
return filteredTopics
}
}
})
I've simplified your code for the sake of ease, but see the below example on how to achieve this (if i've understood your question correctly):
new Vue({
el: "#app",
data() {
return {
selectedRoom: null,
rooms: [
{name: 'room 1', topicId: 1},
{name: 'room 2', topicId: 2},
{name: 'room 3', topicId: 3}
],
topics: [
{id: 1, name: 'topic 1', options: ['one', 'two', 'three']},
{id: 2, name: 'topic 2', options: ['four', 'five', 'six']},
{id: 3, name: 'topic 3', options: ['seven', 'eight', 'nine']}
],
selectedTopicOption: null,
}
},
computed:{
selectedRoomTopic() {
const selected = this.selectedRoom
return (selected)
? this.topics.find(x => x.id === selected.topicId)
: null
}
}
})
<div id="app">
<label>Select a room</label>
<select v-model="selectedRoom">
<option disabled selected>Rooms</option>
<option v-for="room in rooms" :value="room">
{{ room.name }}
</option>
</select>
<div v-if="selectedRoomTopic">
<label>Select a Topic</label>
<select v-model="selectedTopicOption">
<option disabled selected>Topics</option>
<option v-for="option in selectedRoomTopic.options" :value="option">
{{option}}
</option>
</select>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
I am unable to bind selected option in dropdown control. I don't want whole object of $scope.Types inside $scope.obj. It should just have value of $scope.Types inside $scope.obj.type
var app = angular.module("myApp", []);
app.controller("MyController", function($scope) {
$scope.types =
[
{ label: "Pizza", value: 1 },
{ label: "Cakes", value: 2 },
{ label: "Pastry", value: 3 }
];
$scope.obj = { type : 1 };//I want dropdown selected value to be updated in type variable
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<ul ng-app="myApp" ng-controller="MyController">
<select name="status" ng-model="obj.value"
ng-options="type.value as type.label for type in types track by type.value">
<option value="">Select Types</option>
</select>
</ul>
I am not getting what wrong I am doing here.
var app = angular.module("myApp", []);
app.controller("MyController", function($scope) {
$scope.obj = {};
$scope.types =
[
{ label: "Pizza", value: 1 },
{ label: "Cakes", value: 2 },
{ label: "Pastry", value: 3 }
];
$scope.obj.value = 2;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<ul ng-app="myApp" ng-controller="MyController">
<select name="status" ng-model="obj.value"
ng-options="type.value as type.label for type in types">
<option value="">Select Types</option>
</select>
</ul>
Like this?
var app = angular.module("myApp", []);
app.controller("MyController", function($scope) {
$scope.$watch('selectedValue', function(newValue, oldValue) {
if (newValue){
$scope.obj.type = newValue.value;
}
});
$scope.types =
[
{ label: "Pizza", value: 1 },
{ label: "Cakes", value: 2 },
{ label: "Pastry", value: 3 }
];
$scope.obj = { type: 1 };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<ul ng-app="myApp" ng-controller="MyController">
<select name="status" ng-model="selectedValue"
ng-options="type as type.label for type in types track by type.value">
<option value="">Select Types</option>
</select>
{{ obj.type}}
</ul>
I'm new on Angular, and i'm pretty stuck on a simple select problem.
i did a simple select which iterate my scope to populate the select, but after a user click on an option (which are well created), my select becomes blank with no selection inside, and if i click it again there are no options visible.
below is my code:
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.searchFilterDispatcher = {};
$scope.searchFilterDispatcher.distributionCode = [{
id: 1,
label: 'dist1'
}, {
id: 2,
label: 'dist2'
}];
});
<script
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js">
</script>
<select ng-model="searchFilterDispatcher.distributionCode"
ng-options="item as (item.label | uppercase) for item in
searchFilterDispatcher.distributionCode"
class="form-control"
id="distributionCode">
<option >{{'SELECT_A_VALUE' | translate}}</option>
</select>
Any hint?
You should change your ng-model like following. It works in snippet
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.searchFilterDispatcher = {};
$scope.searchFilterDispatcher.distributionCode = [{
id: 1,
label: 'dist1'
}, {
id: 2,
label: 'dist2'
}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<select ng-model="val" ng-options="item as (item.label | uppercase) for item in searchFilterDispatcher.distributionCode" class="form-control" id="distributionCode">
</select>
</div>
In VueJS I am setting model data based on user actions. I want to access the model from a method to update an element.
In the code below, when the user changes the first select list, I want to update the second select list to show the id property of the first list. As it is the upper list works OK but the lower list id property is not updated on upper list change:
<html lang="en">
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.1/vue.js"></script>
</head>
<body>
<div id="editor">
<form id="query" methods="GET">
<div id="form_container" class="row">
<div class="form-group">
<label for="choice-selector">Choices</label>
<select class="form-control" id="choice-selector" v-model="choice_id" v-on:change="refreshOptions">
<option v-for="item in choices" v-bind:value="item.id">
{{ item.name }}
</option>
</select>
<span>Current choice id: {{ choice_id }}</span>
<br>
<label for="option-selector">Options</label>
<select class="form-control" id="option-selector" v-model="option_id" >
<option v-for="item in options" v-bind:value="item.id">
{{ item.name }}
</option>
</select>
<span>Current option id: {{ option_id }}</span>
</div>
</div>
</div>
<script>
let index = 0;
new Vue({
el: '#editor',
data: {
choice_id: '1',
choices: [
{ id: '1', name: 'Choice A' },
{ id: '2', name: 'Choice B' },
{ id: '3', name: 'Choice C' }
],
option_id: '1',
options: [
]
},
ready: function startFetch() {
this.refreshOptions();
},
methods: {
refreshOptions: function refreshOptionList() {
console.log(">>refreshOptionList() index:" + index);
const vm = this;
const newOptions = [{ id: index, name: 'Option based on choices list id: ' + vm.choice_id }];
vm.$set('options', newOptions);
index += 1;
}
},
});
</script>
</body>
</html>
Any ideas?
In Vue 2.x vm.$set is an alias for Vue.set and it takes 3 parameters: target, key and value so you should use it like this:
vm.$set(this, 'options', newOptions);
Or you can just assign newOptions to this.options
this.options = newOptions;
Working example: https://plnkr.co/edit/lFDm7wxb56h81EAwuUNc
var demoApp = angular.module('myApp', []);
demoApp.controller('QaController', function($scope, $http) {
$scope.loopData = [{}, {}];
$scope.questions = {
model: null,
availableOptions: [
{id: '1', name: 'What is your childhood name?'},
{id: '2', name: "What is your first school?"},
{id: '3', name: "What is your first job place?"},
{id: '4', name: "What is your pet name?"}
]
};
$scope.submit = function() {
$scope.result = $scope.loopData;
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp">
<div class="wrapper wrapper-content middlealigen col-sm-12" ng-controller="QaController">
<form ng-submit="submit();">
<div ng-repeat="x in loopData">
<h5>Q. {{$index + 1}}</h5>
<select class="form-control" name="question-drop" id="question_dropdown" ng-model="x.question" ng-options="option.id as option.name for option in questions.availableOptions">
<option value="">Select Question</option>
</select>
<input type="text" placeholder="Enter Answer" name="answer" class="form-control" ng-model="x.answer" />
<div class="m-b"></div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<div ng-if="result">
<pre>{{result | json}}</pre>
</div>
</div>
</body>
Can you please check my code snippet. Here is two dropdown.
If I select What is your childhood name? from Q. 1 dropdown then this option should be disabled in the Q. 2 dropdown. How can I do that?
var demoApp = angular.module('myApp', []);
demoApp.controller('QaController', function($scope, $http) {
$scope.loopData = [];
$scope.loopData = [{
model: null,
question : "",
availableOptions: [
{id: '1', name: 'What is your childhood name?',disable : false},
{id: '2', name: "What is your first school?",disable : false},
{id: '3', name: "What is your first job place?",disable : false},
{id: '4', name: "What is your pet name?",disable : false}
]
},{
model: null,
question : "",
availableOptions: [
{id: '1', name: 'What is your childhood name?',disable : false},
{id: '2', name: "What is your first school?",disable : false},
{id: '3', name: "What is your first job place?",disable : false},
{id: '4', name: "What is your pet name?",disable : false}
]
}]
$scope.changItem = function(index,_id){
$scope.loopData = $scope.loopData.map(function(obj,i){
debugger
if(i > index){
obj.availableOptions.map(function(item){
if(item.id == _id ){
item.disable = true
}else{
item.disable = false
}
return item
})
}else{ debugger
obj.availableOptions.map(function(item){
debugger
if(item.id == _id ){
item.disable = true
}else{
item.disable = false
}
return item
})
}
return obj
});
}
$scope.submit = function() {
$scope.result = $scope.loopData;
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp">
<div class="wrapper wrapper-content middlealigen col-sm-12" ng-controller="QaController">
<form ng-submit="submit();">
<div ng-repeat="x in loopData track by $index">
<h5>Q. {{$index + 1}}</h5>{{x.modelVal}}
<select
ng-change="changItem($index,x.question)" ng-model="x.question" >
<option value="">Select Question</option>
<option ng-disabled="option.disable" ng-repeat="option in x.availableOptions" value="{{option.id}}">{{option.name}}</option>
</select>
<input type="text" placeholder="Enter Answer" name="answer" class="form-control" ng-model="x.answer" />
<div class="m-b"></div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<div ng-if="result">
<pre>{{result | json}}</pre>
</div>
</div>
</body>
You might create a custom filter to be more generic (for more select inputs).
The filter could be:
.filter('excludeEqualAnswers', function() {
return function(input, index, selectedQuestions) {
if (!selectedQuestions[index].question) {
function notExistInSelectedQuestions(output) {
return !selectedQuestions.map(val => val.question).includes(output.id);
}
return input.filter(notExistInSelectedQuestions);
} else {
return input
}
}
})
Then you can filter the options of your select input based upon your custom filter like this:
<select class="form-control" name="question-drop" id="question_dropdown" ng-model="x.question" ng-options="option.id as option.name for option in questions.availableOptions | excludeEqualAnswers:$index:loopData">
<option value="">Select Question</option>
</select>
Here's a working fiddle