AngularJS cascaded drop downs, dependant dropdown not filling in - angularjs

So I have 2 drop downs which need selecting before a third one can be populated.
The problem is even with data coming back the 3rd one isn't populating.
Because of how it is designed each dropdown has it's own controller, with another one for the whole window.
Source widget:
<select class="form-control" required name="dataDomain"
ng-model="customFilters.dataDomain.value"
ng-options="dataDomain.code as dataDomain.shortName for dataDomain in dataDomains"
ng-change="customFilters.dataDomain.loadExtraData()">
<option value="" translate>_NONE_</option>
</select>
source controller:
(function init() {
$scope.customFilters = reportsService.filters;
$scope.customFilters.dataDomain = {
value: undefined,
loadExtraData: function() {
var reportType;
if(this.containsData() && !this.isDisabled()) {
reportType = reportsService.filters.reportType.value;
dictionaryService.getCustomReports({"dataDomain": 'WEE', "country": 'UK')
.then(function ({data}) {
$scope.customReports = data.customReport;
});
}
}
};
})();
The target widget:
<select class="form-control" required name="custom"
ng-model="customFilters.custom.value"
ng-options="c.reportUrl as c.reportName for c in customReports">
<option value="" translate>_NONE_</option>
</select>
whole window controller:
$scope.customReports = [];
As a test to ensure My target widget is looking at the correct location I have also tried in the whole window controller The target dropdown was populated with frank and Joe.
$scope.customReports = [{reportUrl:'hello',reportName:'Frank'},{reportUrl:'hello2',reportName:'Joe'}];
Why isn't the dropdown being populated after the ajax call? (see edit 3)
Edit 1: I have removed excess ajax calls and conditional
functionality from the source widget controller. Hopefully to make
it easier to see. I may have got my brackets wrong.
Edit 2: I did some debugging and the scope ID in the source was 47
and in the target it was 50. I have no idea what these numbers mean,
but it shows I am not storing my data in the same space.
Edit 3: I FIXED IT (by just trying everything), But i don't know why
I moved the customReports data to $scope.customFilters.customReports so the question has changed to WHY IS THIS WORKING!!!!

Because of how it is designed each dropdown has it's own controller,
with another one for the whole window.
This is the key! You have defined $scope.customReports inside wholeController which has a different scope than your dropdown. That is the reason you were able to fix it once you moved it inside $scope.customFilters.customReports which is the same scope as that of the dropdown.
From angularjs documentation
Each AngularJS application has exactly one root scope, but may have
several child scopes.
This blog explains it in detail about Understanding Angularjs scope $rootScope and $scope.

Related

AngularJS Multiple Select not showing preselected options

I have been most part of the morning working on a solution for when I need to assign several values to an entity on my form.
So, the idea is I have an Entity called QualityData and this entity can have different MechanismIdentifiers.
Best solution I thought of, use a multiple select.
All works fine combining both these solutions:
AngularJS selecting multiple options
Get value when selected ng-option changes
I can access the array of selected options, assign it to my entity, etc... But I have a "minor" fallback, which is that I can't get the preselected options (the ones that would come from the server when loading data for editing) to be highlighted in the select field when using a dynamic approach such as <option ng-repeat> or ng-options, it will only work when hardcoding the options. Another bug is that if I wish to add more values than those that are in the preselected array, it will erase all values present in it when using a dynamic approach, working fine when harcoding.
The markup:
<select multiple ng-change="showAlert(selectedValues)" ng-model="selectedValues">
<!--ng-options="resDatasIdOfMechanism as resDatasIdOfMechanism.name for resDatasIdOfMechanism in resDatasIdOfMechanisms track by resDatasIdOfMechanism.id" value="resDatasIdOfMechanism.id">-->
<option value="1">{{resDatasIdOfMechanisms[0].name}}</option>
<option value="2">{{resDatasIdOfMechanisms[1].name}}</option>
<option value="3">{{resDatasIdOfMechanisms[2].name}}</option>
</select>
If I try to use the line that is commented, it's when the marked option will not work
The controller:
$scope.selectedAlready = [{id:1, name:"Based on Antibiogram"}];
$scope.selectedMechanisms=[];
$scope.resDatasIdOfMechanisms = [{id:1,name:"Based on Antibiogram"}, {id:2,name:"Molecular"}, {id:3,name:"Genetic"}];
$scope.selected = $scope.selectedAlready;
$scope.selectedValues = [];
$scope.$watch('selected', function(nowSelected){
$scope.selectedValues = [];
if( ! nowSelected ){
return;
}
angular.forEach(nowSelected, function(val){
$scope.selectedValues.push( val.id.toString());
console.log("look");
});
});
$scope.showAlert=function(listOfMultipleChoices){
//alert(object);
}
EDIT to add jsfiddle link which is working but I still haven't found solution to original question: https://jsfiddle.net/StevenEvenSteven/ybapx09w/
There is a typo in your code.
Add a comma after '$scope' in your controller definition
fiddleApp.controller('myFiddle', ['$scope', function($scope) {
I've forked your jsfiddle and it is working as you expected.

ng-model of <select> in a custom directive does not get saved in IE , works in Chrome and Firefox

<form>
<div ng-if="record.title" class="customClasses" ng-repeat="record in $.basevm.recordsperPage">
<manycustomDirective data-record="record"></manycustomDirective>
</div>
</form>
Multiple records are getting loaded using above custom directive and there are multiple pages.
This manycustomDirective.cshtml again has some more custom directive like below , which shows dropdowns using "select"
<single-choice ng-if="record.type == 1" data-record="record" ></single-choice>
<multi-choice ng-if="record.type == 2" data-record="record" ></multi-choice>
In single-choice directive's cshtml file , I have select + options
<select class="customclassdeginedinLESS" ng-model="record.id" >
<option value=""></option>
<option value="{{choice.id}}" ng-repeat="choice in record.choices">{{ choice.text }}</option>
</select>
Issue is
For IE , only one value from all the pages and custom directives gets saved but in chrome and FF everything gets saved.
I tried using track by choice.id and track by $index but it didnt work.
Trying to write a listener on ng-change of select inside "link" function of CUSTOM directive , I assigned hardcoded value to scope.ngModel , but still it doesnt work.
link(scope: any, element: any, attrs: ng.IAttributes) {
scope.ngchangeListener= function (item) {
scope.ngModel = '00000000';
}
According to the angularJs document, there are some rules you should be aware of when using IE.
For more details, please see https://docs.angularjs.org/guide/ie
Based on your question I am assuming you want the following behavior: Display a <select> where each record.type is 1 that will allow a user to update the id for that record based on the record.choices available to it.
Please examine the following plunker to see if it resolves your issue.
When run in IE 11 (only version i have access to) modifying a <select> will update the record.id for the appropriate item
plunker
I atttempted to simplify the problem by removing references to your custom directives and swtiched from using an ng-repeat of <option>'s to using ng-options
Assumed version of angular: 1.4.12

AngularJS dropdown selected values need as JSON

I have multiple dropdowns in my application which are populating through a json (which is a map basically) given in controller.
For first dropdown if I select xyz value, then corresponding xyz1 values should come in dropdown and similarly for third dropdown. This all is happening fine currently. But now I want these user selected values to get in json form so that I can send back to backend for further processing. I am not getting selected values but the wrong second dropdown values if I print on console.
codepen and
working plunker
I understand that you need to get values from the dynamic input elements. For that, you need to set ng-model to the input elements, not to the div.
The below updated part would help.
<div ng-init="pageObjectName.pageObjParam={}" ng-repeat="(key , value) in pageObjectName.pageObjMethod">
<input ng-model='pageObjectName.pageObjParam[key]' value='' placeholder="{{key}} - {{value}}"></input>
</div>
Now you can get those values from $scope.pageObjectName.pageObjParam.
Updated Plunker
EDIT
I hope the above part helped to get value from dynamic input fields. Now I suggest you to update the code block like below to get the selected values from dropdown (ie, use one hidden input field for each select) and you will get what you want.
<select id="pageObj" ng-model="pageObjectName.pageObj" ng-options="key for (key,value) in pageData" ng-change="pageObjectName.pageObjParam.pageObj=pageObjectName.pageObj">
<option value=''>Select Page Object</option>
</select>
<input ng-model='pageObjectName.pageObjParam.pageObj' hidden/>
You can have a look at the same plunker now
Your codepen seems to be confusing and not working. As you already have the implemention for dropdown I will continue from here about how to get the data from the drop down and convert the data into a JSON.
After getting the data from the dropdown create a JSON object and store it.
I have written a small example to show how to store the data.
$scope.selectedState = function(item) {
var output = {};
output.name = item.name;
$scope.viewOutput = output;
};
Update:
I tried hard but could not get the values using angular way. If you are still looking for an answer then we can use basic javascript way. Refer plunker for the same.
$scope.submitMyForm = function() {
/* while compiling form , angular created this object*/
var pgObj = $scope.pageObj;
var pgClass = $scope.pageClass;
var pgMethod = $scope.pageObjMethod;
var pgObjvalue = document.getElementById('pageObj').value;
var pgClassvalue = document.getElementById('pageClass').value;
var pgMethodvalue = document.getElementById('pageMethod').value;
$scope.output = {'object' : pgObjvalue, 'class': pgClassvalue, 'method': pgMethodvalue};
console.log(data);
};
Working Plunker.
P.S: If you figured out the answer using angular way then do let me know after posting it in the answer section.

How to bind data depending on if checkbox is checked?

Just getting started on Angular, I'm using checkboxes to determine which parameters get sent during a get request (this is my attempt):
<input type="checkbox" ng-click="submit('color[]', 'red')"/>
<input type="checkbox" ng-click="submit('color[]', 'green')" checked/>
<input type="checkbox" ng-click="submit('color[]', 'blue')"/>
I have a variable $scope.params that stores the parameters of my http get request. My submit function is very simple:
$scope.submit = function (attribute, value) {
$scope.params[attribute] = value;
};
It simply adds color[] to the params object. Unlike radio, checkbox values can be stored as arrays and submitted as such: api?color[]=red&color[]=green as my backend is PHP this is the preferred format. However my submit function simply overwrites this every time. I'm not sure how to store multiple params with the same "key".
My other problem is that ng-click is not appropriate for this task as it doesn't take in the current state of the checkbox. Notice that my green checkbox is initially loaded as checked. Is there a way to bind this to my $scope.params object?
Ideally I want to implement something like:
$scope.params = {
"color[]" = ['red', 'green', 'blue']
};
According to Semicolon's answer below, I can use:
<input type="checkbox" ng-model="params.colors[]" ng-true-value="'red'"/>
<input type="checkbox" ng-model="params.colors[]" ng-true-value="'blue'"/>
<input type="checkbox" ng-model="params.colors[]" ng-true-value="'green'"/>
But naming anything with "[]" just breaks the code.
Checkboxes, like all input elements, are supported with ng-model. This core directive is a cousin of ng-bind. It says "the state of this element represents this model". Its behavior is determined by the input type. In the case of a checkbox, the value you are modeling is going to be boolean typically, since a checkbox is fundamentally a "boolean" input (checked/unchecked == true/false).
<input type="checkbox" ng-model="colors.red"/>
In the controller function:
$scope.colors = {
red: false,
green: true,
blue: false
};
Actually you can map checked/unchecked to non-boolean values too, using ng-true-value and ng-false-value. You can read more about these and other options for ng-model with checkboxes in the Angular docs:
https://docs.angularjs.org/api/ng/input/input%5Bcheckbox%5D
The core difference between ng-bind and ng-model is that the former is unidirectional (just a view) and the latter is bidirectional (the element can be used to change the model).
A more general answer regarding the premise of MVC in Angular:
In the example in your question, you were using a jQuery-like solution to try to achieve binding between the view and controller. This is really not ideal. Only bind a function to click events when you are specifically interested in having something take place "on click".
What if a user uses the tab key and the spacebar to check the box? The model would not get updated.
Or let's say you want to change the value in the model somewhere else -- maybe you have a "reset" button that returns them to the original values. The view would not get updated.
If the connection between the view and the model is all through "actions" it is easy for them to be out of sync. You'd have to make sure you handled every possible way the user could interact with the element and each time you change the data programmatically you would need to push the change to the view explicitly. But using ng-model and ng-bind lets you keep them synced no matter where the model is changed or how the user interacts. Really this is the main point of Angular.

Dynamic default values for dynamically generated ng-model

I am facing problem in populating default values for dynamically generated form fields in using angular. So, I have a login form that generates itself based on the attribtes returned by aREST interface. Therefore for my html page, I just have :
<li ng-repeat="element in elements">
<label>UserName</label>
<input type="{{element.inputType}}" ng-model="{{element.fieldName[element]}}" required="required"/>
The default values are returned in an attribute called placehoder in elements object. following tag gives an idea of the task that I am trying to achieve
<input type="{{element.inputType}}" ng-model="{{element.fieldName[element]}}" required="required" placeholder="{{element.placeholder}}"/>
Finally, when the user clicks submit , I need to post the default value of text field if it has not been changed.
Any help would be highly appreciated.
Thanks
If you can add/use a library like underscorejs or lodash, then you can use their _.defaults() :
var object = { 'name': 'barney' };
_.defaults(object, { 'name': 'fred', 'employer': 'slate' });
// → { 'name': 'barney', 'employer': 'slate' }
with angular only, you could add a directive to your form, that watches 'submit' and sets the default values for you.
Thanks for replying #nilsK, I am very new to javascript frameworks and Angular is the first one that I am having my hand on.
So in my R&D with it , I solved my issue by adding the two arrays of values i.e. FieldName and Placeholder to the scope object that I use to post data to my backend. I assign values to these arrays from the objects(placeholder and fieldName) that recieve from REST service as:
$scope.user={};
$scope.user.FieldNames=[];
$scope.user.FieldValues=[];
angular.forEach($scope.elements,function(value,index){
$scope.user.fieldValues[index] = $scope.elements[index].placeholder;
$scope.user.fieldNames[index] = $scope.elements[index].fieldName;
})
and on the html form, I bind ng-model to the scope array of values that I want to display as defaults in text field.
<input type="{{element.inputType}}" ng-model="user.fieldValues[$index]" required="required" />
Therefore, the default values are posted if user does not change them and if there is a change, updated values are posted.
Any suggestions to improve this solution are most welcome.

Resources