I have successfully Added an angularjs directive into another directive using this code
var newElement = $compile( "<div my-diretive='n'></div>" )( $scope );
$element.parent().append( newElement );
but how can i pass the my-diretive='n' n value dynamically .
$scope.showDirective = function(item){
var newElement = $compile( "<div my-diretive='n'></div>" )( $scope );
//here i want to replace 'n' with item
$element.parent().append( newElement );
}
is it possible to pass the value or any other way to do it?
If myDirective has isolated scope, this will create two-way data binding:
$scope.showDirective = function(item){
$scope.item = item;
// the interpolation will be against $scope with item available on it
var newElement = $compile( "<div my-diretive='item'></div>" )( $scope );
$element.parent().append( newElement );
}
Let us know, if it works for you.
Related
I created my custom directive to encapsulate an uib-datepicker-popup:
'use strict';
angular.module( 'frontendApp' )
.directive( 'inputDate', function(){
var controller = function(){
var vm = this;
function init() {
vm.formats = [ 'dd.MMMM yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate' ];
vm.format = vm.formats[ 0 ];
vm.altInputFormats = [ 'M!/d!/yyyy' ];
vm.dateOptions = {
datepickerMode: 'day',
formatYear: 'yy',
maxDate: new Date(),
minDate: new Date( 1900, 1, 1 ),
startingDay: 1
};
vm.datepicker = {
opened: false
};
};
init();
vm.showDatePicker = function(){
vm.datepicker.opened = true;
};
};
var template = '<div ng-switch on="readonly" >' +
'<div ng-switch-when="true" class="form-control" readonly>' +
'<div readonly name="readonlyText">{{ngModel | date : \'d.MMMM yyyy\'}}</div>' +
'</div>' +
'<div ng-switch-default class="input-group">' +
'<input class="form-control" type="text" uib-datepicker-popup="{{vm.format}}" ng-model="ngModel" ng-model-options="{timezone:\'UTC\'}" is-open="vm.datepicker.opened" datepicker-options="vm.dateOptions" ng-required="true" show-button-bar="false" alt-input-formats="vm.altInputFormats" />' +
'<span class="input-group-btn">' +
'<button type="button" class="btn btn-default" ng-click="vm.showDatePicker()"><i class="glyphicon glyphicon-calendar"></i></button>' +
'</span>' +
'</div>' +
'</div>';
return{
controller: controller,
controllerAs: 'vm',
bindToController: true,
template: template,
restrict: 'EA',
scope :true,
require:'ngModel',
link: function( scope, element, attrs, ngModel ){
// Bring in changes from outside:
scope.$watch( 'ngModel', function(){
if( ngModel ) {
scope.$eval( attrs.ngModel + ' = ngModel' );
}
} );
// Send out changes from inside:
scope.$watch( attrs.ngModel, function( val ){
if( val ) {
scope.ngModel = val;
}
} );
if( attrs.readonly === 'true' ) {
scope.readonly = true;
}
}
};
} );
The html part then is:
<input-date ng-model="form.flight.date"></input-date>
The problem: if the popup shows up, scope.ngModel is initialized correctly from attrs.ngModel. I had a log inside the watcher that showed me that watching attrs.ngModel works perfecly, but watching 'ngModel' or scope.ngModel does only work until i use the datepicker. It works perfectly as long as the datepicker is not triggered.
Just discovered that it works perfectly if i remvoe the
"ng-switch-default". Replacing it with ng-show/ng-hide makes the directive work completely as expected.
Can anyone explain why?
The behavior you see is absolutely correct. When you use structural directives like ng-if, ng-switch, ng-repeat etc. it creates a new scope and copies all attributes of the parent scope. Your model is a primitive (string), so it is fully copied to the new scope and changed within this scope without propagation to the parent one.
What you can do is:
Use object instead of string to pass the ng-model, what I personally find here very awkward
Use ng-model from controller object and not from the scope
Going on with the second approach: you already use bindToController and an isolated scope by scope: true, so just instead of tracking the model with watcher bind it to the controller:
return {
bindToController: true,
scope: {
ngModel: '='
},
...
so ideally you won't even need your link function and in the template instead of
'<div readonly name="readonlyText">{{ngModel | date : \'d.MMMM yyyy\'}}</div>'
use
'<div readonly name="readonlyText">{{vm.ngModel | date : \'d.MMMM yyyy\'}}</div>'
Why ng-hide still works? It does not create a new scope.
while creating custom directive, I am trying to fetch html elements
'<div class="parent">',
'<ul class="item-list">',
'<li ng-repeat="item in ::items" class="item-element">{{item}}</li>',
'</ul>',
'</div>',
'<div class="selector"></div>'
link: function($scope, element, attrs) {
var ta = element[0],
$ta = element;
var itemList = angular.element(ta.querySelector(".item-list"));
console.log(itemList);
var itemEl = itemList[0].children;
console.log(itemEl);
}
itemEl displayed on console
[]
0: li.item-element.ng-binding
1: li.item-element.ng-binding
2: li.item-element.ng-binding
3: li.item-element.ng-binding
length: 4
__proto__: Object
How can I fetch inner html and length of the <ul> in angularjs ?
i don't know more about AJ but you can do it in jquery
$(".parent .item-list li").length;
Fiddle Example
The following is an example where several buttons are rendered via a loop. I was wondering if it is possible to bind events to each button as well during the loop before the buttons are appended to a container. My example doesn't work.
Jquery
function render(){
var input = '',
array = [{'name':'Confirm','title':'This'},{'name':'Cancel','title':'That'}]
$.each(array,function(k,obj){
var name = obj.name;
input += '<h3>'+obj.title+'</h3>';
input += '<input type="submit" name="'+name+'" value="'+name+'"/>';
$(input).find('[name="'+name+'"]').click(function(){
alert(name)
/*** do some ajax things etc ***/
})
})
return input;
}
$('#box').append(render())
Yes but I wouldn't do it the way you are:
function render(target){
var array = [{'name':'Confirm','title':'This'},{'name':'Cancel','title':'That'}]
$.each(array,function(k,obj){
var name = obj.name;
var h3 = $('<h3/>').text(obj.title);
var input = $('<input/>')
.attr('type', 'submit')
.attr('name',name)
.val(name);
input.click(function() {alert('test');});
target.append(h3);
target.append(input);
})
}
$(document).ready(function(){
render($('#box'));
});
So create jquery objects that will be rendered, then attach the event to these objects. Then once the object is built ask jquery to render them.
This way jquery can keep track of the DOM elements, in your example your stringfying everything. Jquery hasn't built the DOM element at the point where your attempting to bind to them.
Fiddle
You need to use filter() to find the element by the name as there is no parent selector to find() within:
$(input).filter('[name="' + name + '"]').click(function(){
alert(this.name)
/*** do some ajax things etc ***/
})
No, you can't bind event handlers to strings. You will need to create HTML elements first. I would recommend to bind single delegated event handler after your HTML string is appended, it's also going to be much better in terms of performance:
function render() {
var input = '',
array = [{'name': 'Confirm','title': 'This'}, {'name': 'Cancel','title': 'That'}]
$.each(array, function (k, obj) {
var name = obj.name;
input += '<h3>' + obj.title + '</h3>';
input += '<input type="submit" name="' + name + '" value="' + name + '"/>';
});
return input;
}
$('#box').append(render()).on('click', 'input[name]', function() {
alert(this.name);
/** do some ajax things etc **/
});
Demo: http://jsfiddle.net/KHeZY/200/
This can be done properly by using event-delegation, But since you concerned, I just written a solution by using .add() and .filter()
function render() {
var input = '',
array = [{
'name': 'Confirm',
'title': 'This'
}, {
'name': 'Cancel',
'title': 'That'
}],
elem = $();
$.each(array, function (k, obj) {
var name = obj.name;
input += '<h3>' + obj.title + '</h3>';
input += '<input type="submit" name="' + name + '" value="' + name + '"/>';
elem = elem.add($(input));
input = "";
});
elem.filter("[name]").click(function () {
alert(this.name);
})
return elem;
}
$('#box').append(render())
DEMO
I have a selection inside a paragraph and want to know what is the selected value, but I get null... Any help? Here is the code:
divWithInfo = document.createElement('div');
divWithInfo.class = 'divWithInfoControls';
divWithInfo.style.position = 'absolute';
divWithInfo.style.top = '10px';
divWithInfo.style.width = '100%';
divWithInfo.style.textAlign = 'center';
var groupToDisplay = '<p id="pSelectGroup" style="display: block;">Select the user group: ';
groupToDisplay += '<select id="selectGroup" onchange="applyGroupSelection()">';
groupToDisplay += '<option selected>Nothing selected</option>';
for ( var g in userGroups )
groupToDisplay += '<option>' + g + '</option>';
groupToDisplay += '</select></p>';
divWithInfo.innerHTML += groupToDisplay;
console.log ( document.getElementById( "selectGroup" ) );
when I apply the function onchange, the "document.getElementById" works fine, only in this case I got null
Looks like you've not appended your divWithInfo to the #document so getElementById can't find it in the DOM tree
Before you call document.getElementById("selectGroup"), remember to, e.g. document.body.appendChild(divWithInfo).
If this is not an option, you may want to consider using divWithInfo.querySelector, i.e.
var foo = divWithInfo.querySelector("#selectGroup");
However, I'd try to avoid this and instead if a reference is required before appending, I would create entirely using DOM methods and not using .innerHTML
I am trying to create a directive , on click of button i need to add text box but when i add 2,3 textbox they all share same scope.
How can i isolate the scope inside directive ??
http://jsfiddle.net/A8Vgk/584/
Code::
angular.module('myApp', []).directive( 'test', function ( $compile ) {
return {
restrict: 'E',
scope: { text: '#' },
template: '<p ng-click="add()">Click me </p>',
controller: function ( $scope, $element ) {
$scope.add = function () {
var el = $compile( "<input type='text' ng-model='user.name' value='hello-World!'>" )( $scope );
$element.parent().append( el );
};
}
};
});
Try $scope.$new() and bind your textbox to this newly created scope:
var el = $compile( "<input type='text' ng-model='user.name' value='hello-World!'>" )( $scope.$new() );
DEMO