Display selected data from dynamically created template of radio buttons - angularjs

I created a custom directive which accepts data from a controller. What it does is that when called, it dynamically creates a layout of radio buttons.
What I want to do is display the selected data upon clicking the radio button.
my Controller:
var app = angular.module('myApp', []);
app.controller('DataController', ['$scope', function($scope){
$scope.gender = {
label: "Gender",
required:true,
valueList: [
{ text: "Male", value: "male" },
{ text:"Female", value:"female" }
]
};
$scope.my = { sel: '' };
}]);
Directive:
app.directive('appleRadio', function(){
return {
restrict: 'E',
require: 'ngModel',
scope: {
fieldOptions: '=options',
fieldModel: '=ngModel',
fieldName: '#fieldName',
},
controller: ['$scope', function($scope) {
}],
link: function(scope, element, attribute, controller) {
element.on('click', function(){
// test1: assign the selected value to $scope.my.sel in controller
scope.$parent.my.sel = scope.selected;
// test2: assign the selected value to ng-model in template
scope.fieldModel = scope.selected;
console.log(scope.selected);
});
},
template: '<label style="text-indent: 1em;" ng-repeat="option in fieldOptions.valueList"> <input type="radio" name="option-{{option.value}}"'+
'id="option-{{value}}" ng-model="$parent.selected" value="{{option.value}}">{{option.text}}'+
'</label>'
};
});
in Index.html:
<div ng-controller="DataController">
<apple-radio field-label="Gender" field-name="oGend" options="gender" ng-model="selectedOption"></apple-radio>
<br/>You Selected (via ng-model): {{selectedOption}}<br/>
You Selected (via controller): {{my.sel}}<br/>
</div>
here's the plunker link:
http://plnkr.co/edit/DBmsFmVXyjuZYE7s9LLa?p=preview

Whenever you make changes to the angular context outside of an angular method/event, you need to call scope.$apply().
So at the end of your onClick handler, call scope.$apply().

Related

Selected item in directive not working

I created a select directive and am using this directive twice. I need to see the selected items of both. What should I do?
HTML
<div select-list="items"></div>
<div select-list="items2"></div>
Controller
var myApp = angular.module('myApp',[]);
myApp.controller('mainController', function($scope) {
$scope.items = [
{
name: "1"
},
{
name: "2"
}
];
$scope.items2 = [
{
name: "3"
},
{
name:"4"
}
];
$scope.selectedValues = [];
});
Select directive
myApp.directive("selectList", function() {
return {
restrict: "EACM",
template: '<select ng-model="selectedValues" ng-options="item.name for item in data"></select>',
scope: {
data: '=selectList'
}
}
});
I need to add selected items of both "selects" into $scope.selectedValues.
I tried through ng-change, but it didn't work.
Your directive use isolated scope, so you can't access from the controller to the directive or from the directive to the controller.
You have to create a new entry.
I let you a fiddle that is working :
https://jsfiddle.net/Lv1q2sh2/1/
// Code goes here
var myApp = angular.module('app', []);
angular.module('app')
.directive("selectList", function(){
return {
restrict: "EACM",
require: 'ngModel',
template: '<select ng-model="selected" ng-change="onSelectedValue()" ng-options="item.name for item in data"></select>',
scope: {
data: '=selectList'
},
link: function (scope, element, attr, ngModel) {
scope.onSelectedValue = function () {
ngModel.$setViewValue(scope.selected);
}
}
}
})
.controller('mainController', function($scope) {
$scope.items = [
{name: "1"},
{name: "2"}
];
$scope.items2 = [
{name:"3"},
{name:"4"}
];
$scope.selectedValues = [];
});
Directive needs to be created properly:
Have a controller for your directive
If you are using isolated scope, make sure to pass selectedValue to the scope.
ex:
Directive:
myApp.directive("selectList", function(){
return{
restrict: "EACM",
template: '<select ng-model="selectedValues" ng-options="item.name for item in data"></select>',
scope: {
data: '=selectList',
ngModel: '='
}
//Add link function here, crate watcher on ngModel and update it back on select dropdown selection.
})};
HTML:
<div select-list="items" ng-model="selectedValue1" ></div>
<div select-list="items2" ng-model="selectedValue2"></div>
Add link function to directive and put a watcher on ngModel, once user makes change in selection, update parent ng-model.

Change text value when button is pressed with directives in angular

Here's my fiddle
I basically want to be able to change the text when a button is pressed. I have tried with both $observe and $watch inside link, but I still don't manage to get it working.
Code:
(function(){
angular.module('app', [])
.directive('testDirective', function(){
return {
restrict: 'E',
scope: {
title: '#'
},
template: '<div>this is a {{ title }}</div>',
link: function(scope, element, attrs) {
//?
}
};
});
})()
You need to pass data as scope variable, you should not pass it as a string if you want to track changes.
check this fiddle, replace counter data with your desired data. Hope this helps
<div ng-controller='myctrl'>
<test-directive title="counter"></test-directive>
<hr></hr>
<button type="button" ng-click = 'onclickbutton()'>Change names</button>
</div>
(function(){
angular.module('app', [])
.controller('myctrl',function($scope){
$scope.counter = 0;
$scope.onclickbutton = function(){
$scope.counter++;
}
})
.directive('testDirective', function(){
return {
restrict: 'E',
scope: {
title: '='
},
template: '<div>this is a {{ title }}</div>',
link: function(scope, element, attrs) {
}
};
});
})();

AngularJS controller inside directive with binding

I have this simple code of my directive:
app.directive('ngModal', function ($parse) {
return {
restrict: 'E',
template: document.getElementById('ng-modal').innerHTML,
replace: true,
controller : "#",
name:"controllerName",
}
})
<ng-modal controller-name="ModalCtrl"></ng-modal>
And this is my controller:
app.controller('ModalCtrl', ['$scope', function ($scope) {
$scope.model = 'default text'
}])
<div ng-controller="ModalCtrl">
<input type="text" ng-model="model">
</div>
I want, that model field inside my Directive will updated automatically. But I see "default text" always inside directive and changed inside controller. How can I bind it?
You have to add a service to keep information between controllers. Controllers are always created per "view" so your ng-modal and div have different controllers in use, this is why model data is not updated between them.
Fast example:
app.service('sharedData', function() {
var sharedData = {
field: 'default text'
};
return sharedData;
});
app.directive('ngModal', function () {
return {
restrict: 'E',
template: '',
replace: true,
controller : "#",
name:"controllerName",
}
});
app.controller('ModalCtrl', ['$scope', 'sharedData', function ($scope, sharedData) {
$scope.model = sharedData;
}]);
<ng-modal controller-name="ModalCtrl">{{model.field}}</ng-modal>
<div ng-controller="ModalCtrl">
<input type="text" ng-model="model.field">
</div>

Directive to load data from service, present it with select and bind to model with ng-model

I'm stuck creating a 'countries' directive which load data from a service, shows a list of countries in a select control and allow to bind the selected country to a model with ng-model:
Here is the fiddle: http://jsfiddle.net/4hg4cu9p/1
The view:
<div ng-controller: 'personCtrl'>
<countries ng-model='birthCountry'/>
</div>
The code:
var app = angular.module('myApp', [])
app.controller('personCtrl', ['$scope', function($scope) {
$scope.birthCountry = 'CO';
}]);
app.service('Country', [
'$http', function($http) {
return {
list: function() {
return $http.get('http://restcountries.eu/rest/v1/region/americas', {cache: true});
}
};
}]);
app.directive('countries', [
'Country', '$log', function(Country, $log) {
return {
restrict: 'E',
template: "<select data-ng-model='selectedValue' data-ng-options='country.name for country in countries track by country.alpha2Code'></select?",
require: 'ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
Country.list().then(function(countries) {
scope.countries = countries.data;
});
}
};
}]);
I want to use the ngModelController to:
1.- Set the country in select control when model birthCountry changes.
2.- Change the model birthCountry when user change the select control.
The model is saving the birthCountry as ISO code ('CO' = Colombia, 'US' = United States)
Here is the fiddle: http://jsfiddle.net/4hg4cu9p/1
UPDATE:
Thanks to #PSL and #apairet, here is the jsfiddle working:
http://jsfiddle.net/4hg4cu9p/3/
Since you are specifying ng-model at the directive node, do no specify it at the template instead just use replace:true option in the directive so ng-model will be applied automatically.
Try
{
restrict: 'E',
replace:true,
template: "<select data-ng-options='country.alpha2Code as country.name for country in countries'></select>",
require: 'ngModel',
Demo
Here is a working plunkr: http://plnkr.co/edit/zw5vfjkkESJ78ypCWggi
use an isolated scope, to avoid collision between different instances of your directive
while not strictly required (see http://plnkr.co/edit/e9Vs8AwK5Aqx2G4ZmYVw), I prefer not to use ngModel as custom attribute of a directive --> use of 'my-model'. UPDATE Following your comment and the answer of #PSL, here is another plunker using ng-model and the directive option replace: true http://plnkr.co/edit/YVp6CauBWg3sMLrjwoQL
I bound the model to country.alpha2Code so Colombia is selected
The JS has been modified like this:
var app = angular.module('myApp', []);
app.controller('personCtrl', ['$scope', function($scope) {
$scope.birthCountry = 'CO';
}]);
app.service('Country', [
'$http', function($http) {
return {
list: function() {
return $http.get('http://restcountries.eu/rest/v1/region/americas', {cache: true});
}
};
}]);
app.directive('countries', [
'Country', '$log', function(Country, $log) {
return {
scope: {
myModel: '='
},
restrict: 'E',
template: "<select ng-model='myModel' data-ng-options='country.alpha2Code as country.name for country in countries' track by country.alpha2Code'></select>",
link: function(scope, element, attrs) {
console.log('I am called');
Country.list().then(function(countries) {
console.log(countries);
scope.countries = countries.data;
});
}
};
}]);
and your markup:
<div ng-controller="personCtrl">
<countries my-model="birthCountry"></countries>
{{birthCountry}}
</div>

Correct way to handle angular directive "after render"

I have a directive in which I want to apply a jQuery plugin. The plugin needs assess the element value during its initialization. But the "link" function in a directive runs before the element has been fully processed by Angular.
Is using a $timeout the correct way to look at an element after it has rendered? What delay should be applied? How do you know this timeout will work consistently across systems and browsers of varying processing power?
http://jsfiddle.net/fergal_doyle/DnrEm/3/
HTML:
<div ng-app="app" id="ng-app" ng-controller="test">
<div ng-repeat="item in list">
<label>{{item.title}}
<input type="checkbox" someplugin ng-checked="item.checked">
</label>
</div>
</div>
JS:
var app = angular.module('app', []);
app.controller("test", function ($scope) {
$scope.list = [{
title: "A",
checked: true
}, {
title: "B",
checked: false
}, {
title: "C",
checked: true
}];
});
app.directive("someplugin", function ($timeout) {
return {
restrict: "A",
link: function (scope, element, attrs) {
// too soon
console.log($(element).prop("checked"));
// works
$timeout(function(){
console.log($(element).prop("checked"));
},0);
}
};
});
Try this instead:
app.directive("someplugin", function () {
return {
restrict: "A",
link: function (scope, element, attrs) {
// works
scope.$watch(attrs.ngChecked,function(value){
console.log(value);
});
}
};
});
DEMO
When working with mvc structure like angular, we should not listen to the views for changes as we should not care about when angular updates the views.
We should listen to the model instead as model is where we store the state of the app.

Resources