What I would like to achieve is set a radio button's state according to the data retrieved from the server in AngularJS.
What makes this more special is that I need to show a div based on a condition (the car has 1 and only 1 assigned to it).
If the car is so-called isSingleUser
, the div contains the radio buttons needs to be visible, otherwise we need to hide it.
Finally, after a lot of struggling, I even have the solution to achieve this, but I ran into some interesting obstacles what I want to share with others for reference and I still have some questions regarding the alternative "solutions".
The simplest (and working) solution
We have 3 cars, the Cars service will GET the particular car according to the chosen link.
Only car1 and car2 are isSingleUser
so the div should only visible for those cars.
You can see that the radio button's state changes according to the
car.isMonitoringAutoEnablementSet
JSON property.
This was my first attempt, but I couldn't see the code working at that time, I used the
value property of the input, wrongly, because the ng-value is better.
More specifically, the value
property on input cannot handle boolean values as booleans (and not stringified)
therefore angular couldn't map the boolean value false
to "false"
and the same goes with the true
value.
If I used ng-value
, everything is fine.
Note that the plateNumber for each car is visible on the page.
Let's see what I tried afterwards:
Magic with promise
My assumption was that the data for car is not downloaded yet and the template rendered
before the controller received the data and store it to $scope.car
So I added this code for the controller:
$scope.car = Cars.get({carId: $routeParams.carId})
.$promise.then(function(car) {
$scope.automonitoring_state = car.isMonitoringAutoEnablementSet;
$scope.isSingleUser = car.isSingleUser;
});
and modified the view according to the new variables:
<h1 class="title">{{car.plateNumber}}</h1>
<div class='ng-hide' ng-show='isSingleUser'>
<p class='paragraph'>automatic
<form name="myForm" class="toggle">
<input type="radio" name="state" ng-model="automonitoring_state" ng-value="true">on
<input type="radio" name="state" ng-model="automonitoring_state" ng-value="false">off
<button class="button" disabled>save</button>
</form>
</p>
</div>
Note that the plateNumbers are disappeared from the page, clearly showing that some problem
occured while fetching the data for the car
variable. Only the new variables had a
value in the scope
(automonitoring_state
and isSingleUser
).
Somehow even if I put a simple console.log()
inside the then function on the promise, the
car
variable will not hold the data for the car, strange...
This solution also seems like a workaround, because I need to define new variables in the
scope
, but if I save the car's state through the service, I need to sync back my new
variables to the $scope.car
so this one is definitely a no-go for me.
Resolve with the help of a controller scope function
Then I googled and googled, found some advices on Stackoverflow, and so on.
Hey, there is resolve
which is good for passing some variables into controllers before the view is rendered, that's exactly what I want.
Naively, I tried to invoke a controller function from the routeProvider
like this :
when('/driver/cars/:carId', {
templateUrl: 'partials/driver_car.html',
controller: 'DriverCarController',
resolve: 'DriverCarController'.resolveCar
})
and of course added the function in question to the controller:
$scope.resolveCar = {
car: ['$routeParams', 'Cars',
function($routeParams, Cars) {
return Cars.get({
carId: $routeParams.carId
}).then(function(car) {
console.log('resolve');
return car;
}, function() {
return [];
});
}
]
};
The result is: nothing, no console.log
at all, proving that the function was not invoked.
Another working solution with passing the variable from resolve
This trial is a slightly modified version of the solution above.
The Cars
service is only used from the $routeProvider
, if the promise returns the value, it is saved to the car
variable.
.when('/driver/cars/:carId', {
templateUrl: 'partials/driver_car.html',
controller: 'DriverCarController',
resolve: {
car : function (Cars,$route) {
return Cars.get({carId: $route.current.params.carId})
.$promise.then(function (response) {
return response;
});
}
}
})
The only thing to change in the controller is to add 'car'
to the injection list and save
the parameter to the $scope
.
controllers.controller('DriverCarController', ['$scope', '$routeParams','car', 'SecurityEvents',
function($scope, $routeParams, car, SecurityEvents) {
$scope.car = car;
console.log(car);
}
]);
Any help is appreciated about judging between the most viable approach, providing some information about the intended use cases of each alternative.
Thanks!