Changing a dropdown value results in: Cannot read property entityState of undefined - angularjs

I'm working on an existing AngularJS app where I need to add a new view. In the new view, there is a dropdown which triggers this error every time the value is changed. The dropdown loads all the data correctly. It's only when the value is changed that something goes wrong.
<select class="form-control form-controls input-sm" ng-model="vm.retailer.state" ng-options="state.code as state.name for state in vm.states track by state.code">
<option value="">-- Select a State --</option>
</select>
Here's the error:
TypeError: Cannot read property 'entityState' of undefined
Drilling into the first line on the stack trace, the error is happening here:
https://localhost:44398/bower_components/breezejs/breeze.debug.js:5284:20
It's inside this method:
function setNpValue(context, rawAccessorFn)
Here's the 'context' object. It all looks good:
context: Object
entityAspect: EntityAspect
newValue: "AL"
oldValue: null
parent: Retailer__Model
property: NavigationProperty
propertyName: "state"
__proto__: Object
Down inside the method is where the error is happening.
if (newValue != null) {
var newAspect = newValue.entityAspect;
if (entityManager) {
if (newAspect.entityState.isDetached()) {
if (!entityManager.isLoading) {
entityManager.attachEntity(newValue, EntityState.Added);
}
NewValue is accurately reflecting the new value I selected ("AL" in this case), so it is not null. However, on the next line down, newValue.entityAspect is undefined, so newAspect also ends up being undefined. As a result, when we get to this line:
newAspect.entityState.isDetached()
The error occurs.
I can post the entire controller for the view of where the dropdown exists, if that will help. But it seems like overkill. Looking for any help I can get. I'm pretty new to Angular.
EDIT / UPDATE:
I thought I had found the solution. As the solution to this question:
Dropdown in AngularJS has Correct Text, but Wrong Value
I had added "track by state.code" to the dropdown. In trying to troubleshoot THIS problem, I removed it. After a refresh, this error went away. WAHOO! But my joy was short lived. A short time later, the error came back. And now I'm back to square one.

Ok, I was able to solve this problem. Only it has created another. The problem here was in how I was building my dropdown:
<select class="form-control form-controls input-sm" ng-model="vm.retailer.state" ng-options="state.code as state.name for state in vm.states track by state.code">
<option value="">-- Select a State --</option>
</select>
I changed it to:
<select class="form-control form-controls input-sm" ng-model="vm.retailer.state" ng-options="state as state.name for state in vm.states">
<option value="">-- Select a State --</option>
</select>
And this error went away. But the thing is, I had added made this change to solve the problem I posted about here:
Dropdown in AngularJS has Correct Text, but Wrong Value
So now I'm back to trying to solve that issue.

I ran into this issue as well when I updated angular from 1.3.x to 1.4.x. When I converted back to angular 1.3.x, it went away. I assume there is something in the Breeze Angular Service that was broken by angular and has not been fixed by breeze yet.

Related

"Required" validation doesn't work in <select> with default value

I have a required <select> field:
<select name="service_id" class="Sitedropdown" style="width: 220px;"
ng-model="ServiceID"
ng-options="service.ServiceID as service.ServiceName for service in services"
required>
<option value="">Select Service</option>
</select>
When it is empty, the form should display a "Select service" error message. Here's a working plunker.
It works fine when you intentionally selects the empty option. But when you reload the page, the service_id is empty by default and there is no validation. How to make AngularJS validate the default value?
Your code:
ng-show="myForm.service_id.$dirty && myForm.service_id.$invalid"
This means - if value is dirty (was changed) and is invalid. Remove first and you'll get what you want.
Validation checks are only run after the value bound to ng-model is changed at least once, or when the user attempts to submit the form. If that was not the case, all the required fields of a form would be shown with error right after page loading, which would be a pretty undesirable behavior.
That's why you only see the error when selecting something else and then changing it back to the empty value.

How to pre-select option from <select> tag in Angular with options from a different controller?

I'm using two controllers here. One, productComponentsController, handles a call to our database that pulls back an array of productComponent objects. The other, AddEditArticleController, controls the 'Create New / Edit Existing Article' page.
On my Add/Edit Article page, I want a <select> to populate with productComponents, and, if I am editing an existing Article, to be pre-selected with that Article's current productComponent.
Simple as this seems, I cannot make the field pre-select with the existing productComponent, though it does populate the <select> with them correctly. I've tried ngRepeat and ngOptions and both work for populating the dropdown, but neither works for pre-selecting the existing productComponentID from the array returned by the server.
My HTML, using ngOptions:
<!-- productComponentsController as pvm, AddEditArticleController as vm -->
<select id="componentBox"
ng-model="vm.selectedComponent"
placeholder="Select a Product Component"
ng-change="vm.changeProductID()"
class="form-control input-md"
ng-options="component.name for component in pvm.productComponents track by component.id"></select>
My HTML, using ngRepeat:
<!-- productComponentsController as pvm, AddEditArticleController as vm -->
<select id="componentBox"
ng-model="vm.selectedComponent"
placeholder="Select a Product Component"
ng-change="vm.changeProductID()"
class="form-control input-md">
<option value="{{component.id}}"
ng-repeat="component in pvm.productComponents"
ng-selected="vm.selectOption(component.id)"
ng-bind-html="component.name"></option>
</select>
<!-- vm.selectOption() returns true if the current option's ID equals the productComponentID of the current Article. Therefore this option would be selected. -->
In my AddEditArticleController, I set vm.selectedComponent equal to the productComponentID of the Article that was returned by the database, in the promise.then() of my call. While vm.selectedComponent does change, this doesn't do anything to the dropdown.
Also, in my generated HTML, I get the option: <option value="? number:47 ?"></option> (for an Article where the productComponentID is = 47). Apparently this happens as a result of the model being set to an unknown value but I don't know why the model would be set to anything other than an integer id.
Is this because my select is accessing multiple controllers, or am I missing something obvious here? Any help is greatly appreciated, let me know if more info is needed.
I believe you're looking for ng-init...
<!-- productComponentsController as pvm, AddEditArticleController as vm -->
<select id="componentBox"
class="form-control input-md"
placeholder="Select a Product Component"
ng-change="vm.changeProductID()"
ng-model="vm.selectedComponent"
ng-init="vm.selectedComponent=productComponentID"
ng-options="component as component.name for component in pvm.productComponents track by component.id"></select>
So it turns out that because the model has to be a string, I have to cast the vm.selectedOption to a string whenever it's changed (in this case, in the vm.selectOption function) using String(). This is using ngRepeat. ngInit seems to have no bearing on how my code works.
Boom, that's it, and my code works.

ng-model not working with ng-repeat

I'm trying to figure out why the ng-model is not working with the ng-repeat.
There is my code:
$scope.availableCountries = [];
APIUtility.getCountries().then(function(data){
$scope.availableCountries = data;
$scope.filters.country = "AZ";
});
<select id="eventprice" class="searchpage_select" ng-model="filters.country">
<option value="all">show all</option>
<option ng-repeat="countries in availableCountries" value="{{countries.country_iso}}" ng-class="{'element_selected' : filters.country == countries.country_iso}">{{countries.name}}</option>
</select>
where:
availableCountries is an object from an API call (well formed, trust me)
$scope.filters is an object containing a lot of filters (including country)
The problem is that if i change the ng-model before or after the API call, the select statement is not updated, i think that if i update the scope before angular has the time to execute his ng-repeat, ng-model stop working and will not update the field.
i added the ng-class to prove that filters.country has the right value (ng-class statement returns true when needed and add the class in the right place, so filters.country contains the right value).
I don't know if i was clear enough. Thanks all for your time!
Use ng-options instead of an ng-repeat on an option field.
<select id="eventprice"
class="searchpage_select"
ng-model="filters.country"
ng-options="country.country_iso as country.name for country in availableCountries">
<option value="all">show all</option>
</select>
Problem is in
$scope.filters.country = "AZ";
Try this updated jsfiddle
http://jsfiddle.net/HB7LU/15021/

angular select with 2 item selected

I have a form with a few listbox loaded from a service: most of them are working correctlty, but 3 have a problem: the list is populated correctly, the ng-model variable is set correctly, but the the item is not selected.
Checking with batarang found this:
<select class="required form-control ng-pristine ng-valid ng-touched" data-ng-options="tipoVia.id as tipoVia.descrizione for tipoVia in vm.tipiViaEdit" data-ng-model="vm.recordSelect.tipoVia" data-ng-change="vm.filtroTipoViaEdit()">
<option value="0" selected="selected" label="(--)">(--)</option>
...
<option value="62" label="SVINCOLO">SVINCOLO</option>
<option value="63" selected="selected" label="TRAVERSA">TRAVERSA</option>
<option value="64" label="TRAVERSA DI">TRAVERSA DI</option></select>
...
for same strange reason looks like that two items are flagged with selected: do you know when this may be happens? I have looked a few times but I don't understand how I can do this.
Update:
After the call to the server to receive the data, I set the options and compare with the model to see if is found in the array, and the value is found
this.tipiViaEdit = data.tipiVia;
this.tipiViaEdit.forEach(myString => {
if (myString.id === this.recordSelect.tipoVia) {
alert("value found");
}
});
Luca
finally I found the problem and I share to solution hoping may be useful for others: in the page I'm using a grid to show a list of objects, and selecting one of the rows the object is used in the editing form.
Looks like that the problem was that the same object is bound both to the grid and to the components in the form, giving different result with differents properties: some of the fields in the form was bound correctly, others not.
I rehydrate the object from the server, downloading a new one along with the list components and this way the form works.

How can I detect when a USER changes the value in a select drop down using AngularJS?

I have the following:
<select data-ng-model="selectedTestAccount" data-ng-options="item.Id as item.Name for item in testAccounts">
<option value="">Select Account</option>
</select>
It was suggested to me that I could watch for the value of this select to change with the following:
$scope.$watch('testAccounts', function(){
/* get updated values and update other select "model" on success*/
alert("hello");
});
But this does not seem to work. For one thing it gives an alert as soon as the select appears on the screen and before the user has selected anything. Also am I correct in saying that I should be watching for a change in selectedTestAccount? Finally one more question. How can I show the value of selectedTestAccount in an alert box?
As said, you can get it as the first argument, no need to get it from scope. Use
$scope.$watch('selectedTestAccount', function(newValue){
alert(newValue);
});
Beware that you always get a undefined as the first change for a $watch.
What about putting an "ng-change" to your select?
In your example it would be something like this:
<select data-ng-model="selectedTestAccount" ng-change="updateSelectedAccount(selectedTestAccount)" data-ng-options="item.Id as item.Name for item in testAccounts"></select>
And then in your controller
$scope.updateSelectedAccount = function (selectedTestAccount) {
console.log(selectedTestAccount);
}
P.S. Sorry, just noticed how old this question is :) Hope this might help somebody in the future.

Resources