I am working with angular 1.5.6 component. I am trying to use the output binding ('&') but impossible to get it work. I have plunkered my issue.
Code for index.html :
<body ng-app="MyApp">
<my-view></my-view>
</body>
Code for the component for which I want to use output binding :
app.component('myInput', {
template: [
'<div class="form-group">',
'<label>{{$ctrl.label}}</label>',
'<input placeholder="{{$ctrl.placeholder}}" class="form-control" ng-model="$ctrl.fieldValue"/>',
'</div>'
].join(''),
controller: function() {},
bindings: {
label: '#',
placeholder: '#',
fieldValue: '=',
onUpdate: '&'
}
});
Code for the parent component (output binding is done with the attribute on-update):
app.component('myView', {
template: [
'<div class="container">',
' <h2>My form with component</h2>',
' <form role="form">',
' <my-input on-update="$ctrl.updateParam()" label="Firstname" placeholder="Enter first name" field-value=$ctrl.intermediaryData.firstName ></my-input>',
' </form>'
].join(''),
controller: function() {
var ctrl = this;
ctrl.userData = {
firstName: 'Xavier',
lastName: 'Dupont',
age: 25
};
ctrl.intermediaryData = {
firstName: ctrl.userData.firstName,
lastName: ctrl.userData.lastName,
age: 25
};
function updateParam(){
console.log("I have updated the component");
}
}
});
My bad, I have forgotten to put ng-change in input component. I managed to solve the issue like this :
app.component('myInput', {
template: [
'<div class="form-group">',
'<label>{{$ctrl.label}}</label>',
'<input ng-change="$ctrl.change()" placeholder="{{$ctrl.placeholder}}" class="form-control" ng-model="$ctrl.fieldValue"/>',
'</div>'
].join(''),
controller: function() {
var ctrl = this;
ctrl.change = function(){
ctrl.onUpdate();
}
},
bindings: {
label: '#',
placeholder: '#',
parentParam: '#',
fieldValue: '=',
onUpdate: '&'
}
});
Related
I want's to get the value of ng-model within the the ng-repeat on my own directive and use the value of that ng-model in the directive for a fuction.
here is a plunker to see code in action :
https://plnkr.co/edit/MaI8DOtdc4yucXgNo05p?p=preview
here is my directive code :
(function() {
'use strict';
angular.module('barname.rtEditor', [])
.directive('rtEditor', rtEditor);
function rtEditor() {
return {
restrict: 'E',
replace: true,
templateUrl: 'rt-ht.html',
compile: compile
};
function compile() {
return {
post: function(scope, element, attrs) {
scope.com = {
inp: [{
name: 'video',
model: scope.vimodel,
command: 'insertHTML',
modelcommand: scope.vimodel
}, {
name: 'pic',
model: scope.pimodel,
command: 'insertImage',
modelcommand: scope.pimodel
}, {
name: 'link',
model: scope.linkmodel,
command: 'createLink',
modelcommand: scope.linkmodel
}]
};
scope.$watch('vimodel', function(newValue, oldValue) {
console.log('vim model watch :-> ', newValue);
});
scope.$watch('texmodel', function(newValue, oldValue) {
console.log('text model watch :-> ', newValue);
});
scope.execIn = function(cmd, val) {
console.log('cmd val :->', cmd + ' | ' + val);
scope.vimodel = '';
scope.texmodel = '';
};
}
};
}
}
})();
and here is the html code :
<div>
<div ng-repeat="inp in com.inp" id="{{inp.name}}">
<label>{{inp.name}} :</label>
<input type="text" ng-model="inp.model" />
<span ng-click="execIn(inp.command, inp.modelcommand)">doIt!</span>
</div>
<br>
<hr>
<br>
<div>
<label>widout ng repeat:</label>
<input type="text" ng-model="texmodel" />
<span ng-click="execIn('textIn', texmodel)">doIt!</span>
</div>
</div>
I can easily get the value of the ng-model without ng-repeat
This question already has answers here:
Recursion in Angular directives
(9 answers)
Closed 7 years ago.
Edit: Just came across this SO post. It best answers my questions.
How would you implement the following recursively/better:
HTML
<div ng-controller='MainController as vm'>
<div ng-repeat='tango in vm.tangos'>
<p>{{ tango.text }}</p>
<div ng-repeat='subtango in tango.children'>
<p>{{ subtango.text }}</p>
<div ng-repeat='subsubtango in subtango.children'>
<p>{{ subsubtango.text }}</p>
<!-- ... -->
</div>
</div>
</div>
</div>
JS
angular
.module('app', [])
.controller('MainController', MainController)
;
function MainController() {
var vm = this;
vm.foo = 'bar';
vm.tangos = [{
text: '1',
children: [
{
text: '1a',
children: []
},
{
text: '1b',
children: [
{
text: '1bi',
children: []
}
]
}
]
}];
}
Using a directive doesn't seem to work (plnkr):
HTML
<div ng-controller='MainController as vm'>
<div ng-repeat='tango in vm.tangos'>
<tango tango='tango'></tango>
</div>
</div>
tango.html
<p>{{ tango.text }}</p>
<div ng-repeat='tango in tango.children'>
<tango tango='tango'></tango>
</div>
directive
function tango() {
return {
restrict: 'E',
scope: {
tango: '&'
},
templateUrl: './tango.html'
};
}
I assume that it's instantiating(probably not the right word) the directive even when tango.children is empty. If so, I'm not sure how to prevent that.
Check this demo: Plunker.
Define a template and use $compile to do the trick:
.directive('item', ['$compile', function( $compile ) {
var itemTemplate =
'<div>{{ text }} # of children: {{children.length}}</p>' +
'<div ng-show="children.length > 0">' +
'<div ng-repeat="i in children">' +
'<div item children="i.children" text="{{i.text}}">{{ i | json }}</div>' +
'</div>' +
'</div>' +
'</div>';
return {
restrict: 'AE',
scope: {
children: '=',
text: '#'
},
// template: itemTemplate
link: function (scope, element) {
element.html('').append( $compile( itemTemplate )( scope ) );
}
}
}]);
Here is a custom radio buttons:
The angular HTML code:
<div ng-app="app">
<div ng-controller="ctrl" class="sm-box">
<p>Please select a mode:
<sm-radio model="mode" value="MODE1" label="One" ng-click='mode="MODE1"'></sm-radio>
<sm-radio model="mode" value="MODE2" label="Two"></sm-radio>
<sm-radio model="mode" value="MODE3" label="Three"></sm-radio></p>
<p>Selected mode is: {{mode}}</p>
</div>
</div>
The corresponding JavaScript:
var app = angular.module('app', []);
app.controller('ctrl', ['$scope', function( $scope ) {
$scope.mode = 'MODE1';
}]);
app.directive('smRadio', ['$compile', function($compile) {
return {
restrict: 'E',
template: function( tElt, tAttrs ) {
tElt.addClass( 'sm-radio' );
tElt.append(
'<input type="radio"' +
' name="' + tAttrs.model + '"' +
' ng-model="' + tAttrs.model + '"' +
' value="' + tAttrs.value + '"' +
' /><label>' + tAttrs.label + '</label>'
);
if( ! tElt.attr('ng-click')) {
// This is a first try
tElt.attr('ng-click', 'mode="' + tAttrs.value + '"' );
// this is a variant
tElt.ngClick = 'mode="' + tAttrs.value + '"';
// None has effect...
$compile(tElt); // compilation here had twice elements!!!
}
}
};
}]);
The problem is "One" is clickable and sets the model "mode" to "MODE1" but "Two" and "Three" are not, only the radio buttons may select "MODE2" or "MODE3".
As you can see in the HTML source, the first have "ng-click" attribute when the other have not. I'm trying to add "ng-click" attribute in my directive, by code but I'm unsuccessful.
How can I add "ng-click" attribute in a directive?
EDIT: Answers guide to not use ng-click at all, so title has been updated
It is considered best practice to pass values to directive from "outside world" by using isolated scope. As you can see, it makes it easier too:
var app = angular.module('app', []);
app.controller('ctrl', ['$scope', function( $scope ) {
$scope.mode = 'MODE1';
}]);
app.directive('smRadio', function($compile) {
return {
restrict: 'E',
scope: {
model: '=',
value: '#',
label: '#'
},
template: '' +
'<input type="radio" name="name" ng-model="model" value="value"' +
' ng-checked="model==value" ng-click="model=value">' +
'<label ng-click="model=value">{{label}}</label>',
compile: function(tElt) {
tElt.addClass( 'sm-radio' );
}
};
});
Here's working example: http://jsbin.com/fejori/3/edit?js,output
(In case of this much code in 'template' attribute of a directive, I'd move it to outside html file and link it instead by using templateUrl attribute)
Here's doing it without ng-click. fiddle: http://jsfiddle.net/HB7LU/14244/
var app = angular.module('app', []);
app.controller('ctrl', ['$scope', function( $scope ) {
$scope.modes = [
{label: 'MODE 1', value: 1 },
{label: 'MODE 2', value: 2},
{label: 'MODE 3', value: 3}
];
$scope.selected = 2;
}]);
app.directive('smRadio', function() {
return {
restrict: 'E',
scope: {model: '=', selected: '='},
template: function( tElt, tAttrs ) {
return '<label ng-repeat="radio in model"><input type="radio" ng-value="radio.value" name="modes" ng-model="selected" ng-change="change(radio.value)">{{radio.label}}</label>';
},
link: function(scope, elem, attrs){
scope.change = function(val){
scope.selected = val;
}
}
};
});
Here is exactly what I want, largely inspired by tomek answer, simplified and the idea of label in place of div of Ervald answer.
var app = angular.module('app', []);
app.controller('ctrl', ['$scope', function( $scope ) {
$scope.xmode = 'MODE2';
$scope.ymode = 'MODE_B';
}]);
app.directive('smRadio', function() {
return {
restrict: 'E',
scope : {
model: '=',
value: '#',
label: '#'
},
template:
'<label class="sm-radio"' +
' ng-model="model">' +
'<input type="radio" name="{{model}}"' +
' ng-model="model"' +
' ng-value="value"' +
' ng-checked="model==value"> {{label}}</label>'
};
});
.sm-box {
background-color: lightgray;
border : solid 1px;
padding : 4px;
width : 500px;
}
.sm-radio {
background-color: lightblue;
color : #fff;
display : inline-block;
border : 1px solid darkgray;
border-radius : 8px;
padding : 8px;
}
.sm-radio>input {
width : 24px;
height : 24px;
vertical-align: text-bottom;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="ctrl" class="sm-box">
<p>Please select a Xmode:
<sm-radio model="xmode" value="MODE1" label="One"></sm-radio>
<sm-radio model="xmode" value="MODE2" label="Two"></sm-radio>
<sm-radio model="xmode" value="MODE3" label="Three"></sm-radio></p>
<p>Selected mode is: {{xmode}}</p>
<p>Please select a Ymode:
<sm-radio model="ymode" value="MODE_A" label="A"></sm-radio>
<sm-radio model="ymode" value="MODE_B" label="B"></sm-radio>
<sm-radio model="ymode" value="MODE_C" label="C"></sm-radio></p>
<p>Selected mode is: {{ymode}}</p>
</div>
</div>
I have an angular directive for data insert. And now I want to use same angular directive for data edit/update, but my problem is, the input value is not shown in the input text field. My code is given below:
directive (js) :
dirApp.directive("inputDesign", function () {
return {
restrict: 'E',
transclude: true,
replace: true,
scope: {
inputName: '#',
inputNameText: "#",
inputValue: '#',
inputObject: '=',
checkInput: '&'
},
templateUrl: '../../template/_inputDesign.php'
};
});
template _inputDesign.php:
<div class="form-group">
<!-- {{inputObject[name]}} and {{inputValue}} value is not shown -->
<input type="text" value="{{inputObject[name]}}" class="form-control" ng-model="inputObject[name]" name="{{inputName}}" placeholder="Enter {{inputNameText}}">
</div>
html code ::
<input-design
input-name="a_gradeName"
input-name-text="Grade Name"
input-value="some value" // not work
input-object="gradeTbl.gradeName"
check-input="checkInput(gradeTbl.gradeName, gradeTbl.gradeName[name])">
</input-design>
js code ::
/* grade model */
$scope.gradeTbl = {
'gradeName': {
'name': 'a_gradeName',
'a_gradeName': 'some value',
'display': 'Grade Name',
'status': 'initial',
'regExpr': 'Alphanumeric'
}
};
$scope.gradeTbl.gradeName.a_gradeName = "this is test"; // not worked
$scope.gradeTbl.gradeName.name= "this is test x";
In your _inputDesign.php, change value and ng-model from {{inputObject[name]}} to inputObject.name.
My best guess is that is has to do with this bit:
scope: {
inputName: '#',
inputNameText: "#",
inputValue: '#',
inputObject: '=',
checkInput: '&'
},
I would try changing inputValue to
inputValue: '=',
Here is another answer about the difference between = and # in scope.
What is the difference between '#' and '=' in directive scope in AngularJS?
A little difficult to explain,
we have worked through this sample
https://egghead.io/lessons/angularjs-understanding-isolate-scope
but its not quite matching what we are trying to achieve.
we have built a controller which simply sets myData
ClinicalNotesCtrl.controller('notesController', function notesController($scope, $http, $modal, $log) {
$scope.myData = { name: "Moroni", age: 50, result: "Sodium" };
$scope.changename = function (h) {
h.name = "Simon";
h.age = "34";
h.result = "This is a test";
}
});
Below is the directive called kid. This just simply prints out the value
Results.directive("kid", function () {
return {
restrict: "E",
// scope: { myValue: '=simon' },
// scope:{},
template: '<input type="text" ng-model="myData.name">{{myData.name}}' // '<div>{{$scope.timelineactivitydata}}</div>',
};
});
and finally this is the HTML page,
<kid simon="myData"></kid>
<label ng-click="changename(myData)">Change Name</label>
<kid simon="myData"></kid>
<label ng-click="changename(myData)">Change Name</label>
<kid simon="myData"></kid>
<label ng-click="changename(myData)">Change Name</label>
What we are trying to achieve is to somehow relate a particular label to a kid directive, so that when clicking on the label, only the related kid will change its name, rather than all of them.
Hope that makes sense,
As requested in the comments,
please see the plunker :-
plnkr.co/edit/3NMBNTrLT29EIFNo9lbA?p=preview
I am posting a solution here but I am not sure if it solves anything for you.
JS code
var myApp = angular.module('myApp', []);
myApp.controller('notesController', function notesController($scope, $http) {
$scope.myData = [{ name: "Moroni", age: 50, result: "Sodium" },
{ name: "Naomi", age: 50, result: "Sodium" },
{ name: "Rambo", age: 50, result: "Sodium" }
];
$scope.changename = function (h) {
h.name = "Simon";
h.age = "34";
h.result = "This is a test";
};
})
.directive("kid", function () {
return {
restrict: "E",
scope:{
myData:"=simon",
changed:"&change"
},
template: '<input type="text" ng-model="myData.name"/><span>'
+'{{myData.name}}</span><label '
+'ng-click="changed({\'data\':myData});">'
+'Change Name</label><br/>'
};
});
HTML
<div ng-app="myApp" >
<div ng-controller="notesController" >
<kid ng-repeat="data in myData" simon="data" change="changename(data)">
</kid>
</div>
</div>