I have two select-element that are bound to a model in angular. The first should show a list of processes, the second a list of variables belonging to the process. My datamodel looks like this:
"processes": [
{
"name": "proces1",
"variables": [
"var1",
"var2"
]
},
{
"name": "proces2",
"variables": [
"var3",
"var4"
]
}
]
The result of my selection needs to end up in a 'slider' object in the 'sliders' array on the scope:
$scope.sliders =
[
{
process : "process1",
tag : "var1",
}
]
I've implemented the selects as below, inspired by this jsfiddle.
<tr ng-repeat="slider in sliders track by $index">
<td><select name="processSelect" ng-model="slider.process" ng-options="process.name for process in slider.processes"></select></td>
<td><select name="variableSelect" ng-model="slider.tag" ng-options="v for v in slider.process.variables"></select></td>
</tr>
The approach works, however if my model is already filled only the variableSelect is selected. The process select is not. This is caused because the processSelect uses a a list of process dictionaries instead of strings (which are stored in the model).
What can I do to achieve this? How does one normally accomplish this in angular?
I fixed this by changing my data model slightly to:
"processes": {
"process1": [
"var1",
"var2"
],
"process2": [
"var3",
"var4"
]
}
then I changed the ng-options to:
<tr ng-repeat="slider in sliders track by $index">
<td><select name="processSelect" ng-model="slider.process" ng-options="key as key for (key, value) in processes"></select></td>
<td><select name="variableSelect" ng-model="slider.tag" ng-options="value for (key, value) in processes[slider.process]"></select></td>
</tr>
basically following the angular docs on ng-options.
Related
I am new to web development and AngularJS and I have been struggling with how to go about this. Sorry for the bad English.
I use an ng-repeat that creates the correct number of dropdowns I need as this needs to be dynamic. The dropdowns have a label like:
Test1: <dropdown here>
Test2: <dropdown here> ...etc.
I have a HTTP request that returns an array. If the array has "Test1 State1" in it, I would like the dropdown for Test1: to change to State1 on default. (continues with all the Tests)
How can I go about this?
HTML
<div ng-repeat="o in options track by $index">
<label for="{{::$o}}" class="col-xs-3">{{o}}:</label>
<select id="{{::$o}}" ng-model="stateModel"
ng-options="state.changeToState for state in states"
ng-change="onStateSelect(stateModel.platformReleaseNotes, o)">
{{state}}
</select>
</div>
$scope.states = [
{
changeToState: 'State1',
notes: 'Hello World'
},
{
changeToState: 'State2',
notes: 'Goodbye'
},
{
changeToState: 'State3',
notes: ' is State3'
},
{
changeToState: 'State4',
notes: ' is State4'
}
];
You cannot share model if you want to have different values for all drop downs.
ng-model should be different for all drop downs and this can be achieved by having array of drop downs as below.
$scope.dropDowns = [{
dropDownName: 'Test1:',
id: 'test1',
selectedOption: ''
}, {
dropDownName: 'Test2:',
id: 'test2',
selectedOption: ''
}];
see the running example in
http://plnkr.co/edit/jsAn1jwGkQfxXK5I9G6J?p=preview
A user object is available to the view which populates a form. One of the elements to display information is a drop-down. Two requests are made. One for the user information, and the other for a list of timezones. Both are resolved through a ui-router state like so:
.state('app.userprofile', {
url: '/userprofile',
component: 'user',
resolve: {
user: ['userService', function(userService) {
return userService.fetchUser();
}],
timezones: ['timezoneService', function(timezoneService){
return timezoneService.fetchUsaTimeZones();
}]
}
})
}]);
I have given a read of an article I found online after the select element failed to populate with the users timezone, but the select element still fails to display information.
Question
How do I populate the default select option with data from the user object but populate the options from the second response.
<label for="timezones">Time Zone</label>
<div>
<select name="timezones"
ng-init="userTimezone = $ctrl.user.business.timezone"
ng-change="userTimezone = userTimezone.abbr"
ng-model="userTimezone"
ng-options="item as item.abbr for item in $ctrl.timezones track by item.abbr" class="form-control">
<option value="">{{userTimezone}}</option>
</select>
<p>{{userTimezone}}</p>
</div>
//SECOND REQUEST FOR TIMEZONES
app.factory('timezoneService', ['$http', '$q', function($http, $q){
var factory = {};
factory.fetchUsaTimeZones = function() {
var deferred = $q.defer();
$http.get('../../p3sweb/assets/json/ustimezones.json')
.then(
function(response){
console.log(response.data.ustimezones)
deferred.resolve(response.data.ustimezones)
},
function(errResponse){
deferred.resolve(errResponse)
}
);
return deferred.promise;
}
return factory;
}])
{
"ustimezones": [
{
"value": "Hawaiian Standard Time",
"abbr": "HST",
"offset": -10,
"isdst": false,
"text": "(UTC-10:00) Hawaii",
"utc": [
"Etc/GMT+10",
"Pacific/Honolulu",
"Pacific/Johnston",
"Pacific/Rarotonga",
"Pacific/Tahiti"
]
},
{
"value": "Alaskan Standard Time",
"abbr": "AKDT",
"offset": -8,
"isdst": true,
"text": "(UTC-09:00) Alaska",
"utc": [
"America/Anchorage",
"America/Juneau",
"America/Nome",
"America/Sitka",
"America/Yakutat"
]
}
]
}
UPDATE
It was throwing an error when I had the value of ng-model as $ctrl.user.business.timezone so I have stored the it in a variable userTimezone through the ng-init directive. Updated the code
UPDATE 2
I have it semi-working. It updates all fields though it throws an inconsitent 405 error. Not going to lie, I'm in one of those 'how the hell is this working' situations.
<select name="timezones"
ng-init="userTimezone._abbr = {abbr: $ctrl.user.business.timezone}"
ng-change="$ctrl.user.business.timezone = userTimezone._abbr"
ng-model="userTimezone._abbr"
ng-options="zone.abbr as zone.text for zone in $ctrl.timezones track by zone.abbr" class="form-control">
<option value="">{{userTimezone._abbr}}</option>
</select>
<p>{{userTimezone._abbr}}</p>
You have complex objects as your options. Angular does equality comparison when checking the default value (which is set via the ng-model attribute), so with objects it's comparing object references (via the generated $$hashkey property). Because you have two different object references, once from the timezone list, once from the user, their hashkeys are different. Thus, they're treated as "not equal", so no default gets set.
If you extend your ng-options attribute to use track by, you can select a unique, primitive property where equality comparison makes more sense (such as the abbreviation). Angular will then use this property for equality/uniqueness comparison instead of the hashkey.
So you'd have something like
<select name="timezones" ng-model="$ctrl.user.business.timezone" ng-options="item as item.abbr for item in $ctrl.timezones track by item.abbr"></select>
I converted my Items Array into an indexed object using underscorejs:
$scope.items = _.indexBy($scope.items, 'id');
And now my items looks like this:
$scope.items = {
"1": {
id: 1,
name: "Tizio"
},
"2": {
id: 2,
name: "Caio"
},
"3": {
id: 3,
name: "Sempronio"
},
};
It is exactly what I need.
Now I need to show my items in a Table and I would like to use a plugin that help me to sort, paginate, filter my data easily, so I started to use angular-smart-table. A famous and common one...
I followed the documentation and the final HTML looks like this:
<table st-safe-src="items" st-table="rowItems">
<tr>
<th>id</th>
<th>name</th>
</tr>
<tr ng:repeat="item in rowItems track by item.id">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
</tr>
</table>
Unfortunately it doesn't show my data. I tried to remove smart table and it work fine in a common table.
How can I let it work? What I'm doing wrong? If smart table doesn't support list of Objects, do you know a better plugin that should better fit my needs?
Here a JsFiddle about it.
Thanks
I wasn't sure what you were trying to do with the [].concat(OBJECT), so I changed the way of converting from Object to array using Object.keys and map.
You can check the updated jsfiddle:
https://jsfiddle.net/qfpyu1kL/2/
// Initial values converted to array
$scope.rowItems = Object.keys($scope.items).map(function(key) {
return $scope.items[key];
});
$timeout(function () {
// Add new values
$scope.rowItems.push({ id: 4, name: 'OTHER1' });
$scope.rowItems.push({ id: 5, name: 'OTHER2' });
}, 1000);
I've seen that you were using stSafeSrc, which meant you were expecting asynchronous data, thats why I added the $timeout.
I also updated the HTML to set rowItems in st-safe-srcattribute and st-table to displayedCollection.
I am trying to figure out how to pull data from an array of values, rather than a single value while binding using [(ngModel)] in my Angular 2 app. What I currently have works fine with a single value like this. The single value that's being checked to pull data from the db is whatever's assigned to "value", in this case "staff":
<div class="radio">
<input type="radio" value="staff" name="category" [(ngModel)]="category"> Staff
</div>
This works as expected with a single value. However, one of the values I'm checking against isn't just a single value, but rather an array of values - something like ['advertising', 'accounting', 'adminstration'];
I tried handling this like this in my component:
staff = [
{ value: 1, name: 'advertising' },
{ value: 2, name: 'administration' },
{ value: 3, name: 'accounting' }
];
And then in my view I tried binding to this "staff" array like this:
<div class="radio">
<input type="radio" [value]="staff.value" name="category" [(ngModel)]="category"> Staff
</div>
... but this didn't work. How would I check against an array of values rather than a single value?
I think you want to do a *ngFor and an *ngIf.
Loop through the array and when the array has value=staff then output.
probably change the array name to staffs
*ngFor="let staff of staffs
*ngIf="value=staff.value
I have a table where rows are generated using AngularJS ngRpeat:
<tr ng-repeat="player in division">
<td>{{player.name}}</td>
<td>{{player.score}}</td>
</tr>
The array looks a bit like this:
$scope.divison = [
{
name: "John Doe",
score: "10",
goingUp : true
},
{
name: "Bob Marley",
score: "20"
}
];
Now, what if I wanted to apply ng-class to the table row based on that particular ng-repeat? I would have though this might work:
<tr ng-repeat="player in division" ng-class="'goingUp' : player.goingUp">
<td>{{player.name}}</td>
<td>{{player.score}}</td>
</tr>
Alas this doesn't work. Probably because the ng-class doesn't sit inside that repeat element. How can I get this working though?
Correct syntax is
ng-class="{'goingUp' : player.goingUp}"
It should be able to do so like in this case. You could write a function in to your controllers scope that returns appropriate class:
$scope.isGoingUp = function(player)
{
if (player.goingUp) return "goingUp";
return "notGoingUp";
}
and then call it like this
ng-class="isGoingUp(player)"