ng-change does not work when selected items are changed - angularjs

I'm new to angular, I was trying to display cascading dropdown lists. Here is my html code
<div class="row" ng-controller="createCabsTicketController as tktCreatecabsCntrl">
<select id="LocalCompanyIDForSearch" ng-change="getIXs()" ng-model="createCabsTicket.cabsCompanies.selected" name="LocalCompanyIDForSearch" class="form-control" style="width:100%;">
<option value=" "> </option>
<option ng-repeat="localCompany in createCabsTicket.cabsCompanies"
value="{{ localCompany.CompanyID }}">
{{ localCompany.LongDescription }}
</option>
</select>
<select id="IXCname" name="IXCname" class="form-control" style="width:100%;">
<option value=" "> </option>
<option ng-repeat="ix in createCabsTicket.IXCarrierNames"
value="{{ ix.Interexchange }}">
{{ ix.Interexchange }}
</option>
</select>
And here is my js file contents
app.controller('createCabsTicketController',['$scope','$http',function($scope,$http){
$scope.createCabsTicket = {
cabsCompanies: [],
IXCarrierNames: [],
IXCarrierIds:[]
};
$http.get('http://localhost:52377/api/reference/companies/active', { cache: true }).success(function (data) {
$scope.createCabsTicket.cabsCompanies = data;
});
$scope.getIXs = function (selectedItem) {
var postData = { ActiveOnly: true, CompanyId: selectedItem, CarrierId: "", CarrierName: "", CarrierType: "" };
$http.post('http://localhost:52377/api/reference/interexchanges', postData, { cache: true }).success(function (data) {
$scope.createCabsTicket.IXCarrierNames = data;
});
}
}]);
The web services work and the parent list gets populated just fine. But the ng-change event doesn't get fired. I am not sure what did I do wrong. I have found similar posts but they were not quite helpful to solve my problem. Please help!!

Related

Vue v-for: Dynamicly fill HTML with event handler (#change) from an array into a component template

This is my current setup:
HTML
<question
v-for="question in questions"
v-bind:id="question.id"
v-bind:title="question.title"
v-bind:statement="question.statement"
v-bind:interaction="question.interaction"
#onchange-vg="onChangeVg"/>
</question>
Definition of <question>
var questionComponent = Vue.component('question', {
props: ['id', 'title', 'statement', 'interaction', 'currentQuestion'],
template: `
<div :id="'question-' + id">
<div class="flex my-3">
<div class="py-0"><span>{{ id }}</span></div>
<div>
<p>{{ title }}</p>
<div :class="{'hidden':(id !== this.$parent.currentQuestion), 'block':(id === this.$parent.currentQuestion)}">
<p>{{ statement }}</p>
<span v-html="interaction"></span>
</div>
</div>
</div>
</div>
`
});
Vue
var app = new Vue({
el: '#app',
data() {
return {
vg: null,
currentQuestion: 1,
questions: [
{
id: 1,
title: 'Question 1',
statement: 'Details for question 1',
interaction: `
<select ref="vb-art" #change="$emit('onchange-vg')">
<option disabled value="" selected>Make a choice</option>
<option value="red">Red</option>
<option value="blue">Blue</option>
</select>
`
},
{
title: 'Question 2',
statement: 'Details for question 2',
interaction: `
<select ref="vb-art" #change="$emit('onchange-vg')">
<option disabled value="" selected>Make a choice</option>
<option value="black">Black</option>
<option value="white">White</option>
</select>
`
},
],
}
},
methods: {
onChangeVerguetungsart() {
console.log("Value: " + event.target.value);
currentQuestion++;
},
},
});
Everything is rendered fine. My problem is, that the event handler #change in <select ref="vb-art" #change="$emit('onchange-vg')"> does not fire.
Whe I replace <span v-html="interaction"></span> whit the whole <select ref="vb-art" #change="$emit('onchange-vg')">...</select> code from interaction every thing works fine.
The interactions may be different from question to question. It could be an , a or just a simple link. That's why i try to put the code into the array and not to the component definition.
How can I solve this issue, so that <span v-html="interaction"></span> accepts the event handler from a code snippet that is delivered by an array value?
You should avoid v-html. v-html bind just plain HTML, not Vue directives.
For you case v-html is not necessary. Make array of options from interaction property and generate your markup by vue template.
interaction: [
{value: 'red', label: 'Red'},
{value: 'blue', label: 'Blue'}
]
and in your component
<select ref="vb-art" #change="$emit('onchange-vg')">
<option disabled value="" selected>Make a choice</option>
<option v-for="{value, label} in interaction" :key="value" :value="value">{{ label }}</option>
</select>
update:
IF you have dynamic content, then slot is your friend. (Refer docs
https://v2.vuejs.org/v2/guide/components-slots.html for more examples)
Your component:
<div>
<p>{{ title }}</p>
<div>
<p>{{ statement }}</p>
<slot />
</div>
</div>
And usage
<question
v-for="question in questions"
v-bind:id="question.id"
v-bind:title="question.title"
v-bind:statement="question.statement"
v-bind:interaction="question.interaction"
>
<select ref="vb-art" #change="onChangeVg">
<option disabled value="" selected>Make a choice</option>
<option value="red">Red</option>
<option value="blue">Blue</option>
</select>
</question>
Bonus is, that you don't need to emit anything.
Btw using this.$parent is also not qood idea. Your component is coupled with parent. Use props instead.

Dynamic dropdown select partially working with react redux

Am trying to import angularjs working code to react redux.
In angularjs, this code works very well for dropdown menu but am trying to have it working exactly with react redux.
Here is my issue,
In React Redux, I have success in displaying the records in dependent dropdown menu, but want I want is to get the value of
dependent(second dropdown)
menu data each time a record in the first(Parents) dropdown menu is selected
it seems that fetchRecord(){} is not selecting and calling any data
Angularjs code
<body ng-app='myapp'>
<div ng-controller="fetchCtrl">
<table>
<tr>
<td>State :</td>
<td>
//First/Parents menu
<select ng-model='state_send' ng-change='fetchRecords()'>
<option value='0'>-- Select State --</option>
<option value='1'>provision</option>
<option value='2'>chemicals</option>
<option value='3'>foods</option>
<option value='4'>sports</option>
</select>
</td>
</tr>
<tr>
<td>//Dependent/Child menu :</td>
<td>
<select >
<option value='0'>-- Select User --</option>
<option ng-repeat="user in usersList" value='{{ user.id }}' >{{ user.name }}</option>
</select>
</td>
</tr>
</table>
</div>
<!-- Script -->
<script>
var fetch = angular.module('myapp', []);
fetch.controller('fetchCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.state_send = '0';
// Fetch data
$scope.fetchRecords = function(){
$http({
method: 'post',
url: 'record.php',
data: {state_send:$scope.state_send}
}).then(function successCallback(response) {
$scope.usersList = response.data;
});
}
}]);
</script>
</body>
Partially working code for React-Redux
import React from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { userActions } from '../_actions';
class RecordDropdown extends React.Component {
constructor(props) {
super(props);
this.state = { us: 0};
this.state_send = 0;
}
componentDidMount() {
this.props.dispatch(userActions.getDropdown(this.state_send));
}
fetchRecord(){
this.state_send = 0;
alert(this.state_send);
this.props.dispatch(userActions.getDropdown(this.state_send));
}
render() {
const { rec, recs } = this.props;
return (
<div style={{background:'red'}} className="well col-md-6 col-md-offset-3">
//First/Parents Menu
<select name="this.state_send" id="this.state_send" value={this.state_send} onChange={this.fetchRecord} >
<option value='0'>-- Select State --</option>
<option value='1'>provision</option>
<option value='2'>chemicals</option>
<option value='3'>foods</option>
<option value='4'>sports</option>
</select>
//Child/Dependent Menu
{recs.items &&
<ul><select>
<option value='0' >--select--</option>
{recs.items.map((rec, index) =>
<option key={rec.id} value='{ rec.id }' >{ rec.name} { rec.id }</option>
)}
</select>
</ul>
}
<p>
<input type="text" className="form-control" name="this.state_send" id="this.state_send" value={this.state_send} onChange={this.handleChange} />
</p>
</div>
);
}
}
I forget to bind to bind fetchRecord() functions as per code below and issues solved
this.fetchRecord = this.fetchRecord.bind(this);

Angular Form select- how to show corresponding values from database )postgres, sequelize)?

I am using Angular, Node.js, Sequelize/Postgres, and have a form (select options form). I am trying to make the option fields depend on each other, so for example when a particular first name is picked, only the corresponding last name is being shown in the other select options field. I don't really know how to do that, only found some similar examples but still don't quite understand how to do that when the values are fetched directly from the database and any help would be appreciated.
Angular factory:
app.factory('DoctorsFactory', function($http){
var DoctorsFactory={};
DoctorsFactory.fetchAll=function(){
return $http.get('/api/doctors')
.then(function(docs){
return docs.data;
})
}
return DoctorsFactory;
});
controller:
app.controller('AppointmenController', function ($scope, DoctorsFactory) {
$scope.doctors={};
DoctorsFactory.fetchAll()
.then(function(all){
console.log('bla', all)
$scope.docs=all;
})
});
HTML:
<div class="container">
<h2>Form control: select</h2>
<form ng-submit="searchForDoc(doctors)">
<div class="form-group">
<label for="sel1">Firstname</label>
<select class="form-control" id="sel1" ng-model="doctors.firstname">
<option ng-repeat="doc in docs">{{doc.firstname}}</option>
</select>
<br>
<label for="sel1">Lastname</label>
<select class="form-control" id="sel1" ng-model="doctors.lastname">
<option ng-repeat="doc in docs">{{doc.lastname}}</option>
</select>
<br>
<label for="sel1">Speciality</label>
<select class="form-control" id="sel1" ng-model="doctors.speciality">
<option ng-repeat="doc in docs">{{doc.speciality}}</option>
</select>
<br>
<label for="sel1">Department</label>
<select class="form-control" id="sel1" ng-model="doctors.department">
<option ng-repeat="doc in docs">{{doc.department}}</option>
</select>
<br>
<label for="sel1">School</label>
<select class="form-control" id="sel1" ng-model="doctors.school">
<option ng-repeat="doc in docs">{{doc.school}}</option>
</select>
<br>
</div>
<input type="submit">
</form>
</div>
route:
router.get('/', function(req,res,next){
Doctors.findAll({})
.then(function(alldoctors){
console.log(alldoctors)
res.send(alldoctors);
})
.catch(next);
})
database model:
var Sequelize = require('sequelize');
var db = require('../_db');
module.exports = db.define('doctors', {
firstname: {
type: Sequelize.STRING
},
lastname: {
type: Sequelize.STRING
},
speciality: {
type: Sequelize.STRING
},
department: {
type: Sequelize.STRING
},
gender: {
type: Sequelize.STRING
},
school: {
type: Sequelize.STRING
},
languages:{
type: Sequelize.STRING
}
});

Using ng-option with sorting and custom text

I have the following ng-repeat:
<select class="action-dropdown fade" ng-model="item_value">
<option value="" disabled>Choose an Step</option>
<option ng-repeat="step in steps | orderBy:'+step_number'" ng-if="step.step_number >= active_step" value="{{$index}}">Step {{step.step_number}}</option>
</select>
I am attempting to change this to an ng-option because the following option is popping up and I think this might fix the issue:
<option value="? string:5 ?"></option>
I'm trying to wrap my head around how to include my ng-if statement with the ng-option and to use the word Step $index when displaying the option.
The comprehension expressions are just blowing my mind and I was wondering if anyone could help me out.
This is what I have so far:
<select class="action-dropdown fade" ng-model="item_value" ng-options="$index as step.step_number for step in steps" required>
<option value="" disabled>Choose a Step</option>
</select>
look the snipped as I've commented
I think that the best way (cleaner way) is populate the steps list on change active_step. To access the index you can use the (key,value) syntax
select as label for (key , value) in object
Doc: https://docs.angularjs.org/api/ng/directive/ngOptions
angular.module('app', [])
.controller('DefaultController', function () {
this.item_value = null;
this.steps = [
{ step_number: 5 },
{ step_number: 2 },
{ step_number: 6 },
{ step_number: 3 },
{ step_number: 1 },
{ step_number: 4 },
]
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div data-ng-controller="DefaultController as ctrl">
<select ng-model="ctrl.item_value" ng-options="step as 'Step ' + index for (index, step) in ctrl.steps | orderBy:'+step_number'" required>
<option value="" disabled>Choose a Step</option>
</select>
Selected: {{ ctrl.item_value }}
</div>
</div>

two level ng-options nested object

EDIT: Using only ng-options as much as possible.
How the data looks like:
vm.category = [
0: {
label: 'Label A',
children: [
{
label: 'Label A.1',
value: 'labelA1',
}
]
}
1: {},
2: {}
]
How it will look like in the HTML. Expected HTML
<select>
<optionGroup> Label A </optionGroup>
<option value="labelA1"> Label A.1 </option>
<option value="labelA2"> Label A.2 </option>
<optionGroup> Label B </optionGroup>
<option value="labelB1"> Label B.1 </option>
</select>
How to achieve this without changing the data structure as much as possible?
I tried ng-options="category.children.label group by category.label for category in vm.categoryTree". But the output is
<select>
<optionGroup> Label A </optionGroup>
<option> undefined </option>
<optionGroup> Label B </optionGroup>
<option> undefined </option>
</select>
Easiest way would be to map the data to a format more easily used by the ng-options "group by" expression
angular.module('so', []).controller('snippet', function() {
this.categoru = [{"label":"Label A","children":[{"label":"Label A.1","value":"labelA1"}]},{"label":"Label B","children":[{"label":"Label B.1","value":"labelB1"}]}];
this.options = this.categoru.reduce((flat, group) => {
Array.prototype.push.apply(flat, group.children.map(child => {
return Object.assign({
parent: group.label
}, child);
}));
return flat;
}, []);
console.log(this.options);
});
<form ng-app="so" ng-controller="snippet as vm">
<select ng-model="vm.selected"
ng-options="opt.label group by opt.parent for opt in vm.options track by opt.value">
</select>
<pre>vm.selected = {{vm.selected | json }}</pre>
</form>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
You can do this,
<select ng-model='theModel' ng-change="display(theModel)">
<optgroup ng-repeat='group in collection' label="{{group.Name}}">
<option ng-repeat='veh in group.Fields' value='{{group.Name}}::{{veh.Name}}'>{{veh.Name}}</option>
</optgroup>
</select>
DEMO

Resources