How to solve "of undefined" problem of a service? - javascript

I am calling service in Angular7 at every dropdown option change. But when I change selected option on dropdown I am getting getAllByCountryId of undefined error.
Here is function that calling http service:
countryOnChange(countryId: Guid) {
this.cityService.getAllByCountryId(countryId).subscribe(
res => {
if (res.code === ResponseCode.success) {
res.dataList.map(item => {
this.cities.push({
value: item.id.toString(),
label: item.dataValue
});
});
if (this.formComponent !== undefined) {
this.formComponent.form.controls['cityId'].patchValue(this.cities);
}
}
},
err => {
this.error = true;
});
}
Here is the HTML code that calling above function on every dropdown option change:
<ng-container *ngSwitchCase="'dropdown'" class="col-md-12">
<ng-select [ngClass]="'ng-select'" [options]="input.options" [formControlName]="input.key" [id]="input.key" (selected)="input.onChange($event.value)"></ng-select>
</ng-container>
input.onChange($event.value) and countryOnChange is connected at the backend.
Here is how to call countryOnChange function:
const dropdown2 = new InputDropdown({
key: 'countryId',
label: '',
onChange: this.countryOnChange,
options: this.countries,
value: '',
required: true,
order: 3
});
Error http://prntscr.com/ovjxe7
How can I solve this problem?

I think [ngModel] is needed:
<select [ngModel]="selectedValue" (ngModelChange)="onDropdownChange($event)"
class="form-control">
<option *ngFor="let category of categorylist" [ngValue]="category.id">
{{category.Description}}</option>
</select>
refer to: Angular 2 How to bind selected id in Dropdownlist with model?

getAllByCountryId of undefined error means you are getting this.cityService as undefined.
Check with which this context your function is binding when you are creating the InputDropDown. May be you need to define it like :-
const dropdown2 = new InputDropdown({
key: 'countryId',
label: '',
onChange: this.countryOnChange.bind(this),
options: this.countries.bind(this),
value: '',
required: true,
order: 3
});
Hope this helps.

Related

Capturing Click Event to Pass Into Function in Angular App

I have set up some filters a user can click on in order to filter a list display in my Angular app. The relevant code in my view looks like this:
<md-checkbox *ngFor="let option of categoryFilters.options" [(ngModel)]="option.value" (click)="filterByCategory($event)">
{{option.label}}
</md-checkbox>
You'll notice that I have a "filterByCategory()" function above. What I want to do with that is filter the list according to the value that the user clicks on from the md-checkbox list. So far I haven't been able to capture that value.
I've tried this in my component:
public filterByCategory(option) {
console.log('Category filter ' + option + ' was clicked');
}
But that just prints the mouse event to the console:
'Category filter [object MouseEvent] was clicked'
I also tried using the two-way-bound value, like this:
public filterByCategory(option) {
console.log('Category filter ' + this.option.value + ' was clicked');
}
But that returns 'undefined'.
By the way, the options I'm trying access the values of here look like this in my component:
private categoryFilters = {
enabled: true,
options: [
{ toolbarLabel: 'A', label: 'Option A', value: false },
{ toolbarLabel: 'B', label: 'Option B', value: false },
{ toolbarLabel: 'C ', label: 'Option C ', value: false }
],
text: null
};
What can use to actually get the value that was clicked on, in order to pass that into the filter function?
Try this.
(click)="optionClicked(option)">
optionClicked(option) {
console.log(option.value)
}
UPDATE:
You can also try this:
<md-checkbox *ngFor="let option of categoryFilters.options"
[(ngModel)]="option.value" (change)="filterByCategory(option.label, $event)">
{{option.label}}
</md-checkbox>
filterByCategory(value, checked) {
if(checked) {
console.log(value)
}
}
Original answer:
You could do it like this: I removed the two-way-binding altogether, since we are using $event and value-attribute, so in this case ngModel is redundant. I also use change-event instead of click. So change your template to:
<md-checkbox *ngFor="let option of categoryFilters.options"
value="{{option.label}}" (change)="filterByCategory($event)">
{{option.label}}
</md-checkbox>
And in the component, let's see if the checkbox is checked before actually looking at the option value.
filterByCategory(event) {
if(event.checked) {
console.log(event.source.value)
}
}
This seems to work fine:
Demo

How to display response on the option select ? (vue.js 2)

My component vue.js is like this :
<script>
export default{
name: 'CategoryBsSelect',
template: '\
<select class="form-control" v-model="selected" required>\
<option v-for="option in options" v-bind:value="option.id" v-bind:disabled="option.disabled">{{ option.name }}</option>\
</select>',
//props: {list: {type: String, default: ''}},
mounted() {
this.fetchList();
},
data() {
return {
selected: '',
options: [{id: '', name: 'Pilih Kategori'}]
};
},
methods: {
fetchList: function() {
this.$http.post(window.BaseUrl+'/member/category/list').then(function (response) {
//this.$set('list', response.data);
console.log(JSON.stringify(response.body))
Object.keys(response.body).forEach(function (key) {
console.log(key)
console.log(response.body[key])
this.$set(this.options, key, response.body[key]);
}, this);
});
},
}
};
</script>
The result of console.log(JSON.stringify(response.body)) :
{"20":"Category 1","21":"Category 2","22":"Category 3"}
I want display the response on the value of select. But when executed, on the console exist error like this :
TypeError: Cannot read property 'id' of undefined
Is there anyone who can help me?
The issue you are having is the final this.options variable is an hash nat an array, which should be an input to select element, you can modify you code inside fetchList method like following:
Object.keys(resp).forEach((key) => {
console.log(key)
console.log(resp[key])
this.options.push({
id: key,
name: resp[key]
})
});
Have a look at working fiddle here.

Cannot select default value in dropdown using ng-model and ng-repeat or ng-select in AngularJS

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

Angular change default value of select from filter

I have a select box which is populated with some data from my controller. When an input value changes the contents of the select box should be filtered and a default value should be assigned based on the is default property of the data object.
Is there any way this can be done using angular directives or would it need to be done as a custom filter function doing something along the lines of
angular.forEach(vm.data,function(item){
if (vm.q == item.someId && item.isDefault) {
vm.result = item.value;
}
});
My html looks something like
<div ng-app="myApp" ng-controller="ctrl as vm">
<input type="text" ng-model="vm.q">
<select ng-options="item.value as item.description for item in vm.data | filter:{someId:vm.q}" ng-model="vm.result"></select>
</div>
and my controller looks like:
(function(){
angular.module('myApp',[]);
angular
.module('myApp')
.controller('ctrl',ctrl);
function ctrl()
{
var vm = this;
vm.data = [
{
someId: '1',
description: 'test1',
value: 100,
isDefault: true
},
{
someId: '2',
description: 'test2',
value: 200,
isDefault: false
},
{
someId: '3',
description: 'test3',
value: 100,
isDefault: true
},
];
}
})();
See my plunkr demo here: http://plnkr.co/edit/RDhQWQcHFMQJvwOyHI4r?p=preview
Desired behaviour:
1) Enter 1 into text box
2) List should be filtered to 2 items
3) Select box should pre-select item 1 based on property isDefault set to true
Thanks in advance
I'd suggest you include some 3rd party library, like lodash, into your project to make working with arrays/collections that much easier.
After that you could add ng-change directive for your input.
<input type="text" ng-model="vm.q" ng-change="vm.onChange(vm.q)">
And the actual onChange function in the controller
vm.onChange = function(id) {
var item = _.findWhere(vm.data, { someId: id, isDefault: true });
vm.result = item ? item.value : null;
};
And there you have it.

ng-repeat controller and parent update

I've been reading a lot on angular scopes and inheritance but I can't get my head around this problem. Here is the HTML I'm using:
<div class="sensorquery-sensor" ng-repeat="sensor in query.sensors" ng-controller="SensorsCtrl">
<select class="form-control"
ng-model="selected.sensor"
ng-options="sensor.name for sensor in parameters.sensors">
</select>
<select class="form-control"
ng-model="selected.definition"
ng-options="definition.value for definition in definitions">
</select>
<select class="form-control"
ng-model="selected.operation"
ng-options="operation for operation in operations">
</select>
</div>
As you can see, I have an ng-repeat based on query.sensors. The values stored in this query.sensors array should be simple:
{
name: 'sensor1',
type: 'temperature'
}
But I want to use a child controller: SensorsCtrl to handle more logic per sensor and hide the complexitiy of sensors. A sensor can look like:
{
name: 'sensor1',
attributes: [
'model',
'brand'
],
definitions: [
{
datatype: 'double',
value: 'temperature'
},
{
datatype: 'integer',
value: 'pressure'
},
{
datatype: 'string',
value: 'color'
}
]
}
So it's in my SensorsCtrl controller where I want to put the selection logic:
$scope.$watch('selected.sensor', function(sensor) {
$scope.definitions = sensor.template.definition;
});
$scope.$watch('selected.definition', function(definition) {
if (definition.datatype === 'string') {
$scope.operations = ['Count'];
} else {
$scope.operations = ['Max', 'Min'];
}
$scope.selected.operation = _.first($scope.operations);
});
How do I keep the link with the parent query.sensors[$index] while transforming the sensor as the user selects different sensors and definitions?
Setting up a watcher on selected and updating the query.sensors array triggers an infinite $digest loop.
I found the solution which was right before my eyes:
<div class="sensorquery-sensor" ng-repeat="sensor in query.sensors" ng-controller="SensorsCtrl">
<!-- ... -->
</div>
The sensor is a reference to the original object of the parent query.sensors. An it's created in the scope of the sub-controller.
So in my SensorsCtrl controller, I can just watch:
$scope.$watch('sensor.definition', function(definition) {
/* ... */
});
So I can put hide some complexity in this controller while maintaining a proper link to the original element.
It does not answer the question of maintaining a less complex object but it's a different question I guess.

Categories

Resources