angular ng-options does not render the right value in IE 11 - angularjs

I have two dropdowns with ng-options. One for displaying primary brokers and other for secondary brokers.
The Mark-up is as follows:-
<div class="col-md-4">
<div class="form-group">
<label>Primary Broker: </label>
<button type="button" class="btn-help" tabindex="-1" data-popover="" data-content="Lead JLL broker for the opportunity">
<span class="circle-help">?</span>
</button>
<select class="form-control"
ng-options="jllContact.JllUserId as jllContact.Name for jllContact in controller.primaryJllBrokers"
ng-model="controller.primaryJllContactId"
id="primaryJllContact" data-field='{"name": "Primary Broker", "attribute": "PrimaryJllContact"}'
ng-change="controller.setPrimaryJllContact()"
ng-class="{'req': controller.data.isFieldRequired('PrimaryJllContact'), 'has-error': controller.data.isFieldValid('PrimaryJllContact') == false}"
ng-disabled="!controller.isEnabled('JllContacts')||!controller.canEditBrokerAllocation()">
<option value="">Select Primary Broker</option>
</select>
</div>
</div>
#* Secondary Broker*#
<div class="col-md-4">
<div class="form-group">
<label>Secondary Broker: </label>
<button type="button" class="btn-help" tabindex="-1" data-popover="" data-content="Secondary JLL broker for the opportunity">
<span class="circle-help">?</span>
</button>
<select class="form-control"
ng-options="jllContact.JllUserId as jllContact.Name for jllContact in controller.secondaryJllBrokers"
ng-model="controller.data.SecondaryJllContactId"
id="secondaryJllContact" data-field='{"name": "Secondary Broker", "attribute": "SecondaryJllContact"}'
ng-change="controller.handleSecondaryJllContactChange()"
ng-class="{'req': controller.data.isFieldRequired('SecondaryJllContact'), 'has-error': controller.data.isFieldValid('SecondaryJllContact') == false}"
ng-disabled="!controller.isEnabled('JllContacts')||!controller.canEditBrokerAllocation()">
<option value="">Select Secondary Broker</option>
</select>
</div>
When I change the secondary broker, as seen in the markup I call a method called
handleSecondaryJllContactChange. The method is as follows.
handleSecondaryJllContactChange:()=>
primaryJllContactId = this.primaryJllContactId
this.refreshPrimaryBrokers((primaryBrokers)=> this.primaryJllContactId = primaryJllContactId)
refreshPrimaryBrokers:(callback)->
this.primaryJllBrokers = _.where(this.data.JllContacts, (jllc)=> jllc.Role.ID == 21 && jllc.JllUserId != this.data.SecondaryJllContactId)
if callback? && callback!= undefined && this.primaryJllBrokers!=null && this.primaryJllBrokers != undefined
callback(this.primaryJllBrokers)
As seen from the code, we are setting the ng-model "controller.primaryJllContactId" for the first drop down after the collection controller.primaryJllBrokers has been refreshed.
However, the drop down still shows instead of the correct option in IE 11.
NOTE:
On examining the console, we did notice that ng-model for the first
dropdown controller.primaryJllContactId has the right value. It just
doesn't display correctly in the drop down.
This is happenning only in IE 11. It works perfectly in chrome.
Couple of things we have tried:-
Instead of ng-change="controller.handleSecondaryJllContactChange()" in the second dropdown we tried to have a watch on controller.secondaryJllBrokers
and call the method controller.handleSecondaryJllContactChange().
The second route which we took was based on the assumption that we are setting the ng-model before options are rendered. Hence we took the $timeout
approach. In the handleSecondaryJllContactChange() method shown above we did this in the second line:-
this.refreshPrimaryBrokers((primaryBrokers)=> this.$timeout(=> this.primaryJllContactId = primaryJllContactId))
None of these two approaches worked. Any ideas why this is happening and what is the way to know when options have finished rendering.
Thanks in Advance !!!!

Related

AngularJS - Checkbox not reflecting value from back-end

Have a checkbox which should show yes when true and no when false. Unfortunately, while it does work and it does allow you to change the back-end value when you click it. It constantly shows the value to be false. Any help?
<div class="form-group">
<label for="useAppEntitlements"
class="col-lg-4 col-sm-4 col-xs-4 control-label no-padding-right">Use
Application
Entitlements?</label>
<div class="col-lg-7 col-sm-7 col-xs-7">
<label class="margin-top-5">
<input name="useAppEntitlements" id="useAppEntitlements"
class="checkbox-slider yesno"
type="checkbox"
ng-model="targetEntity.useAppEntitlements"
ng-true-value="1"
ng-false-value="0"
ng-disabled="editMode == false && !isNewSite">
<span class="text"/>
</label>
</div>
</div>
I was wondering where exactly the issue might stem from if it's not showing the correct value when the back-end JSON shows it to be true?
Take a look at this simple plunk I created:
https://next.plnkr.co/edit/TEj3nJLNPIWp77lW?open=lib%2Fscript.js&deferRun=1
You create a $scope.targetEntity object like so:
$scope.targetEntity = {
useAppEntitlements = false;
}
As you can by the console log, every time you click the checkbox it alternates between true and false(0 and 1).

Angular not validating form select

I'm new to angular so bear with me. I have a form with a dropdown, textbox and a button. The user has to select an option from the dropbox and enter a value in the textbox before the form becomes valid.
<form name='personDataSourceForm' novalidate ng-submit='personDataSourceForm.$valid && PersonCtrl.SaveDataItem()'>
<span>Invalid: {{personDataSourceForm.$invalid}}</span><br />
<span>valid: {{personDataSourceForm.$valid}}</span>
<div class="input-group">
<div class="input-group-addon">
<select class="form-control input-sm" required ng-model='PersonCtrl.sp.person.newItem.dataType' ng-options='opt as opt.text group by opt.dataType for opt in PersonCtrl.DataItemTypes'>
<option value="" disabled selected>Choose...</option>
</select>
</div>
<input type="text" class="form-control input-sm" ng-model='PersonCtrl.sp.person.newItem.value' required>
<div class="input-group-btn">
<button class="btn btn-default btn-sm" ng-class="{ 'btn-success' : PersonCtrl.sp.person.newItem.dataType.dataType && PersonCtrl.sp.person.newItem.value }" type="submit">Save</button>
<button class="btn btn-link btn-sm" type="button" ng-click="PersonCtrl.StopAddItem()">Cancel</button></div>
</div>
</form>
I quickly added 2 spans to show the validation state. When both are empty the form shows invalid which makes sense.
As soon as I type in a value in the textbox then suddenly the form is valid even though the dropdown still hasn't been changed.
Why is my dropdown not getting validated? I've even tried this solution AngularJS Dropdown required validation
My initial thought is that you already have that default value selected:
<option value="" selected>Choose...</option>
so it does technically have a value of "", which is fulfilling the required.
I think you will need to look at PersonCtrl.sp.person.newItem. The form becomes valid when both the dataType and value get solid. My guess is the item always has its dataType solid and valid so when the new value is entered the whole form becomes valid.
Why don't your select ad input have a name attribute? The name attribute is necessary for form validations to work properly.
I think form creates a map of name->validity for each input component and it could be that you have omitted it they both (select and input) map to the same validity object. If this is the case, then anyone becomes valid, effectively makes the status of the other one valid as well and hence they are both valid the form becomes valid.
Please add separate names for them and see if the problem is resolved. My opinion above is a strong guess and I have not dived into Angular code to check ng-form's behaviour.

Input validation: Validation message and ng-disabled buttons not working as expected

I have the following code which I'm trying to validate using AngularJS:
<div ng-form="transWizard" novalidate>
<div style="word-wrap:break-word; padding-top:4px; padding-left:14px">
<p style="font-family:'MetricWeb-Regular'; font-size:17.5px;"><span style="font-family:'MetricWeb-Semibold'">Question {{carousel.currentQuestionIndex+1}}:</span> {{carousel.currentQuestionObject.question}}</p>
<ul style="padding-left:30px;">
<li ng-repeat="query in carousel.currentQuestionObject.choices" style="padding-bottom:5px;">
<input class="TWInputField" name="inputname"
type="{{carousel.currentQuestionObject.inputType}}" id="{{query.id}}"
ng-model="query.selected" ng-change="carousel.changeOnSelection(query.selected, query.id)"
value="" ng-value="true" ng-required="{{carousel.currentQuestionObject.inputType === 'radio' || carousel.currentQuestionObject.inputType === 'text' ? true : false}}">
<label for="{{query.id}}" style="font-family:'MetricWeb-Regular';font-size:17px;cursor:pointer"> {{query.question}}</label>
</li>
</ul>
<p class="msg-required" ng-show="transWizard.inputname.$invalid">
Input is required.
</p>
</div>
<div class="carousel-wizard-btn-container">
<div class="carousel-wizard-buttons" ng-click="carousel.wizardPrevious()" ng-hide="carousel.currentQuestionIndex == 0">Previous</div>
<div class="carousel-wizard-buttons" ng-click="carousel.wizardNext()" ng-hide="carousel.currentQuestionIndex == carousel.wizardQuestionSet.length - 1" ng-disabled="transWizard.$invalid">Next</div>
<div class="carousel-wizard-buttons" ng-click="carousel.showResults()" ng-show="carousel.currentQuestionIndex == carousel.wizardQuestionSet.length - 1" ng-disabled="transWizard.$invalid">Finish</div>
</div>
</div>
As you can see, I'm not using the <form> tag, but I've read that it's possible to validate even without using forms thanks to the ng-form directive.
My conditions are to require input only if type is radio or text.
However, when I executed this, I got the following:
ng-disabled is not working for the Next button. I can still click it even though I haven't selected any answers for the required sections.
Validation message only disappears when I click the last item in a set of radio buttoned-questions.
Am I missing something here?
Please help. Thank you.
your validation will not work as expected because u are using same name for input controls in ng-repeat.
you can use ng-form inside ng-repeat like this.
<div ng-form="transWizard" novalidate>
<li ng-repeat="query in carousel.currentQuestionObject.choices" style="padding-bottom:5px;">
<ng-form name="innerForm" >
<input class="TWInputField" name="inputname" type=" {{carousel.currentQuestionObject.inputType}}" id="{{query.id}}" ng-model="query.selected" ng-change="carousel.changeOnSelection(query.selected, query.id)" value="" ng-value="true" ng-required="{{carousel.currentQuestionObject.inputType === 'radio' || carousel.currentQuestionObject.inputType === 'text' ? true : false}}">
<label for="{{query.id}}" style="font-family:'MetricWeb-Regular';font-size:17px;cursor:pointer"> {{query.question}}</label>
<p class="msg-required" ng-show="innerForm.inputname.$invalid">
Input is required.
</p>
</ng-form>
</li>
</div>

ng-repeat radio button 2-way binding issue, only last item set correctly

I am using angularjs to repeat radio button groups with the following code.
<div class="row observation-point"
ng-repeat="observationPoint in question.observationPointList">
<div class="col-md-6 col-sm-6">
<small>{{observationPoint.text}}</small>
</div>
<div class="col-md-4 col-sm-4 col-md-offset-2 col-sm-offset-2">
<label class="radio-inline">
<input type="radio" ng-disabled="observation.status != 'Open'"
name="{{domain.id}}-{{question.id}}-{{observationPoint.id}}"
id="{{domain.id}}-{{question.id}}-{{observationPoint.id}}-1" ng-value="true"
ng-model="observationPoint.observed">{{'observation-domain.html.yes' | translate}} {{observationPoint.observed}}
</label>
<label class="radio-inline">
<input type="radio" ng-disabled="observation.status != 'Open'"
name="{{domain.id}}-{{question.id}}-{{observationPoint.id}}"
id="{{domain.id}}-{{question.id}}-{{observationPoint.id}}-0" ng-value="false"
ng-model="observationPoint.observer">{{'observation-domain.html.no' | translate}}
</label>
</div>
</div>
With angular 1.2.28 this worked fine, however we've recently upgraded to 1.4.2 and now the result is as in the picture below.
The model values are correctly saved and restored (see the true and false values in the image) in the variables, but only the last radio button in the ng-repeat is selected after reloading the page.
Why is this happening, because I really don't understand what the problem is and how to fix this.
nb. observationPoint.observer contains a boolean value not a string
EDIT: i've created a simplified plunker and of course this works as intended :S
http://plnkr.co/edit/tWjizHB8I5FNZVOgdq6J?p=preview
Which would suggest something is wrong with the naming or id's.
However when I check with the developer tools id and name seem fine
I've found a solution, if I change the dynamic names from
name="{{domain.id}}-{{question.id}}-{{observationPoint.id}}"
to
name="observationPoint_{{observationPoint.id}}"
it works without a hitch. I presume there is some sort of loading/timing issue going on. The variables are probably not unique at the moment the UI is rendered and causes only the last item to be set.

angular select $touched validation

I have a form with select and a button that is enabled when the form is validated. It works fine with input box. However, it the $touched does not seem to be working properly for the select. The button is enabled even when select is touched. It is supposed to turn invalid when select is touched. It only turns invalid and the button is disabled when I select an option and then select the default value. I want it to work when select is touched and user the mouse pointer away.
Here is my html:
<form role="form" name="frameVersionEditor" novalidate class="form-horizontal col-md-12">
<div class="row">
<div class="form-group col-lg-2 col-lg-push-1" ng-class="{'has-error' : frameVersionEditor.distributor.$invalid && frameVersionEditor.distributor.$touched}">
<label>Distributor</label>
<select name="distributor" data-ng-model="myDistr" data-ng-options="distributors.key as distributors.value for distributors in distributorOptions" class="form-control" required>
<option value="">Select Distributor</option>
</select>
<span ng-show="frameVersionEditor.distributor.$error.required && frameVersionEditor.distributor.$touched" class="help-block">Please select a distributor</span>
</div>
</div>
</form>
<button data-ng-click="generate()" ng-disabled="frameVersionEditor.$invalid">Generate</button>
Here is my controller:
var myApp = angular.module('myApp',[]);
myApp.controller('myController', ['$scope', function($scope) {
$scope.myDistr = [];
$scope.distributors =
[
{
'key': '0',
'value': 'A'
},
{
'key': '1',
'value': 'B'
},
{
'key': '2',
'value': 'C'
}
];
$scope.generate = function() {
//Do something
};
}]);
I had much the same issue just a short time ago. I solved it by adding a few things to the select field and another entry to the array of possible selections.
First, you want to add an empty or invalid selection to the list of possible selections, the best place is in the [0] slot and you'll see why further down.
vm.distributors = [ "Select Distributor", "A", "B", "C" ];
Next, you need to add and update some Angular Directives for your select field. You want the ng-valid to tell Angular what is acceptable here. You also need to specify that you are starting the field with a "select something else" value and that it is not valid for that value to be selected during submit. Adding a name and id are generally best practice items. The last bit to add is the ng-required directive, since you used novalidate on the form, but it is required that this form item change to something valid. The end result is below:
<div class="form-group col-lg-2 col-lg-push-1" ng-class="{'has-error' : vm.myDistr == vm.distributors[0] && frameVersionEditor.$dirty
|| frameVersionEditor.distributor.$pristine && frameVersionEditor.distributor.$touched}">
<label>Distributor</label>
<select data-ng-model="vm.myDistr" id="myDistr" name="myDistr" ng-init="vm.distributors[0]" class="select form-control skinny" ng-required="true"
data-ng-options="d for d in vm.distributors" ng-valid="vm.myDistr != vm.distributors[0]"></select>
<p class="required" ng-show="vm.myDistr == vm.distributors[0]">*</p>
<p class="good" ng-show="vm.myDistr != vm.distributors[0]">✔</p>
<span ng-show="vm.myDistr == vm.distributors[0] && frameVersionEditor.$dirty || frameVersionEditor.distributor.$pristine
&& frameVersionEditor.distributor.$touched" class="help-block">Please select a distributor</span>
This also was updated to illustrate the simplest implementation (since you are using 0-4 as keys, you don't really need them, just use a basic array). I also changed your code to coincide with John Papa's best practices and added in a red asterisk (for invalid selections) and a green check mark (for a correct selection), as is another good practice (show success as well as failure) in the case of non-English-speaking users.
You also do not need the beginning option you specified originally since my updates handle that nicely.
By request, here is a Plunker.
I hope this helps.
-C§
I have made up this fiddle and everything seems to work fine.
<div ng-app="myApp" ng-controller="myController">
<h1>Select a Distributor</h1>
<form name="form" class="form-horizontal col-md-12" novalidate>
<div class="row">
<div class="form-group col-lg-2 col-lg-push-1" ng-class="{ 'has-error': form.distributor.$invalid && form.distributor.$touched }">
<label>Distributor</label>
<select name="distributor" ng-model="mySelection" ng-options="d.key as d.value for d in myDistr" class="form-control" required>
<option value="">Select Distributor</option>
</select>
<span ng-show="form.distributor.$error.required" class="help-inline">Please select a distributor</span>
</div>
</div>
</form>
<hr/><hr/>
<button class="btn btn-primary" data-ng-click="generate()" ng-disabled="form.$invalid || form.distributor.$touched">Generate</button>
</div>
I have the suspect that maybe the $touched event is not what you think.
Please give me some feedback if I'm wrong!

Resources