Directive function not running - angularjs

I have this directive:
angular.module('colab.dropdown', []).directive('colabDropdown', function(){
return {
restrict: 'A',
transclude: true,
scope: {
ddlist: '=listtoshow',
model: '=modeltosave',
displayField: '=listfieldtoshow',
fieldtoSave: '=listfieldtosave'
},
link: function(scope, element, attrs) {
var ddlist = scope.ddlist,
model = scope.model,
displayField = scope.displayField,
fieldtoSave = scope.fieldtoSave,
rowIdx = scope.rowIndex;
rowIdx = null;
for(var i=0;i < ddlist.length;i++){
if(ddlist[i][attrs.listfieldtosave] == model){
rowIdx = i;
}
}
if(rowIdx !== null){
scope.displayField = ddlist[rowIdx][attrs.listfieldtoshow];
}
console.log(scope.displayField);
scope.selectItem = function(unit) {
console.log(unit);
// var idx = scope[attrs.listtoshow].indexOf(unit);
// scope[attrs.modeltosave] = unit[attrs.listfieldtosave];
// scope.listfieldtoshow = unit[attrs.listfieldtoshow];
};
}
}
});
here is my template:
<div class="radio">
<label>
<input type="radio"
name="chickenEgg"
ng-value="mm.id"
ng-model="formData.chickenEgg"
ng-change="selectItem(mm)"
>
{{mm.name}} - {{mm.year}}
</label>
</div>
I am not able to do the following:
run function selectedItem() in my template when I click the radio.
display the {{displayField}} in the DOM. I can display it in the console (line 38 of the directive) but not in the DOM. see the plunker console**
I can run the selectItem() if I don't have the scope:{...} in the directive.
http://plnkr.co/edit/wuLmJs5f6hVhPEP7OqKS?p=preview
Thank you.

You need to add you add your selectItem() function to angular-hovercard.js file.
$scope.selectItem = function(item) {
console.log(item);
}
Check it Out

Related

Angular modal dialog set inside list items

I'm trying to set a list of two items that open separate modal dialogs in a node.js app. I'm using Jade.
Here's the Jade:
button.login-button(type='button' ng-app='ng-modal') Login
ul
li(open-dialog='modal-to-open') Login
// JUST WORKING ON SIGN UP FOR NOW
li Sign Up
modal-dialog(show='dialogShown' dialog-title='My Dialog' height='100px' width='100px')
p Working
div.loginForm
form(name='loginForm' method='post' action='#' enctype='text/plain')
label(for='user') Username or Email
input(type='text' name='username' id='username' size="39" placeholder='Username or Email' required)
label(for='password') Password
input(type='password' name='password' id='password' size='39' placeholder='Password' required)
I'm using Adam Brecht's modal dialog plugin. I have the js file and the css files attached.
I changed the declaration of the module in the js file to this:
app = angular.module("myApp", ["ngModal"])
I have the list set as a dropdown in my CSS. I wanted the form to display in a modal dialog when the link in the list is clicked, but at the moment the form displays below dropdown box.
What am I missing?
EDIT: This is the js file:
(function() {
var app;
app = angular.module("myApp", ["ngModal"])
app.provider("ngModalDefaults", function() {
return {
options: {
closeButtonHtml: "<span class='ng-modal-close-x'>X</span>"
},
$get: function() {
return this.options;
},
set: function(keyOrHash, value) {
var k, v, _results;
if (typeof keyOrHash === 'object') {
_results = [];
for (k in keyOrHash) {
v = keyOrHash[k];
_results.push(this.options[k] = v);
}
return _results;
} else {
return this.options[keyOrHash] = value;
}
}
};
});
app.directive('modalDialog', [
'ngModalDefaults', '$sce', function(ngModalDefaults, $sce) {
return {
restrict: 'E',
scope: {
show: '=',
dialogTitle: '#',
onClose: '&?'
},
replace: true,
transclude: true,
link: function(scope, element, attrs) {
var setupCloseButton, setupStyle;
setupCloseButton = function() {
return scope.closeButtonHtml = $sce.trustAsHtml(ngModalDefaults.closeButtonHtml);
};
setupStyle = function() {
scope.dialogStyle = {};
if (attrs.width) {
scope.dialogStyle['width'] = attrs.width;
}
if (attrs.height) {
return scope.dialogStyle['height'] = attrs.height;
}
};
scope.hideModal = function() {
return scope.show = false;
};
scope.$watch('show', function(newVal, oldVal) {
if (newVal && !oldVal) {
document.getElementsByTagName("body")[0].style.overflow = "hidden";
} else {
document.getElementsByTagName("body")[0].style.overflow = "";
}
if ((!newVal && oldVal) && (scope.onClose != null)) {
return scope.onClose();
}
});
setupCloseButton();
return setupStyle();
},
template: "<div class='ng-modal' ng-show='show'>\n <div class='ng-modal-overlay' ng-click='hideModal()'></div>\n <div class='ng-modal-dialog' ng-style='dialogStyle'>\n <span class='ng-modal-title' ng-show='dialogTitle && dialogTitle.length' ng-bind='dialogTitle'></span>\n <div class='ng-modal-close' ng-click='hideModal()'>\n <div ng-bind-html='closeButtonHtml'></div>\n </div>\n <div class='ng-modal-dialog-content' ng-transclude></div>\n </div>\n</div>"
};
}
]);
}).call(this);
I just realized I haven't changed the template.

generating a variable-length dropdown based on input value in an AngularJS directive

I want to provide a page selection directive that generates "Page [ 1 ] of x". The number of pages in the dropdown is dependent upon values passed into the directive, so it can't be part of a static template. I'm having a difficult time figuring out how/where to generate the <select><option>...</select>.
I have tried, unsuccessfully, to do it via:
an $observe (and $watch) in link
a function added to $scope in controller, which returns $compile(markup)($scope) (This gives the error Error: [$parse:isecdom] Referencing DOM nodes in Angular expressions is disallowed!)
a sub-directive for the <select> element (The link $observer never seemed to get the recordCount updates, regardless of inherited or shared scope.)
ng-repeat in the template
Here's my mangled code, as it currently stands.
HTML
<x-pager
record-count="{{recordCount}}"
page-size="pageSize"
page-number="pageNumber"
set-page="selectPage(page)"
></x-pager>
JS
module.directive("pager", ["$compile",
function ($compile)
{
return {
template: "<div class='pager' ng-show='recordCount > pageSize'>\
{{recordCount}} results\
<button>« Prev</button>\
page <select>\
<option>#</option>\
</select> of {{calcPages()}}\
<button>Next »</button>\
</div>",
replace: true,
restrict: "E",
scope: {
recordCount: "#",
pageSize: "=",
pageNumber: "=",
setPage: "&"
},
link: function (scope, element, attrs)
{
/*
* We can't build the page selection dropdown until
* we know how many records we have. Register an
* observer to do this when recordCount changes.
*/
attrs.$observe("recordCount", function (recCnt)
{
var html;
var pages;
var i;
if (angular.isDefined(recCnt)) {
html = "<select>\n";
pages = Math.ceil(scope.recordCount / scope.pageSize);
for (i=1; i<=pages; i++) {
html += " <option value='" + i + "'>" + i + "</option>\n";
}
html += "</select>";
console.log("generatePageSelect html", html);
html = $compile(html)(scope);
// add the template content
// angular.element("select.page-selector").html(html);
// template: page <select class='page-selector'></select> of {{calcPages()}}\
}
});
},
controller: function ($scope)
{
$scope.calcPages = function ()
{
return Math.ceil($scope.recordCount / $scope.pageSize);
};
function genPagesArray ()
{
var pages = $scope.calcPages();
var i;
var pagesArray = [];
for (i=0; i<pages; i++) {
pagesArray.push(i);
}
return pagesArray;
}
$scope.pagesArray = genPagesArray();
console.log("$scope.pagesArray", $scope.pagesArray);
// template: page {{generatePageSelect()}} of {{calcPages()}}\
$scope.generatePageSelect = function ()
{
var html = "<select>\n";
var pages = $scope.calcPages();
var i;
for (i=1; i<=pages; i++) {
html += " <option value='" + i + "'>" + i + "</option>\n";
}
html += "</select>";
return $compile(html)($scope);
};
}
};
}
]);
To expand on my comment from earlier, here's a directive that does (most of) what you want it to do.
angular.module('Test', []).controller('TestCtrl', function($scope) {
$scope.pageSize = 10;
$scope.pageNumber = 1;
$scope.recordCount = 30;
}).directive("pager", function () {
return {
template: '<div class="pager" ng-show="recordCount > pageSize">\
{{recordCount}} results\
<button ng-click="pageNumber = pageNumber - 1" ng-disabled="pageNumber <= 1">« Prev</button>\
page <select ng-model="pageNumber" ng-options="i for i in pages"></select> of {{totalPages}}\
<button ng-click="pageNumber = pageNumber + 1" ng-disabled="pageNumber >= totalPages">Next »</button>\
</div>',
replace: true,
restrict: "E",
scope: {
recordCount: "#",
pageSize: "=",
pageNumber: "=",
setPage: "&"
},
link: function (scope, element, attrs) {
attrs.$observe("recordCount", function (count) {
if (angular.isDefined(count)) {
scope.recordCount = parseInt(count);
var i;
scope.totalPages = Math.ceil(scope.recordCount / scope.pageSize);
scope.pages = [];
for (i=1; i<=scope.totalPages; i++) {
scope.pages.push(i);
}
}
});
}
}
});
Plunkr here.

Angularjs dynamically adding controls

Im trying to adding dynamically $scope
app.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, ele, attrs) {
scope.$watch(attrs.dynamic, function (html) {
ele.html(html);
$compile(ele.contents())(scope);
});
}
};});
and my HTML;
<select dynamic="myOption_{{ item.RowId }}" id="select_{{ item.RowId }}" multiple class="chosen" data-ng-model="selectedOption" data-placeholder="Select" data-ng-change="ChangeTopic()"
chosen="directiveOptions"
ng-options="item.Id as item.tag for item in optionsFromQuery"
style="width:100%;">
</select>
angular;
var appsx = "";
for (var i = 0; i < result.item.length; i++) {
var rowIds = parseInt(result.item[i].RowId);
appsx = '<option value="" selected>' + result.item[i].Tags + '</option>';
var controlName = 'myOption_' + rowIds;
controlName = appsx;
}
Example; if I try to $scope.myOption_100 = appsx; it's working but I cannot make dynamically scope
$scope.controlName = 'myOption_' + rowIds; like that.
Try scope.$observe(attrs.dynamic.....

AngularJS Directive using Compile cannot access child elements

My intent was to create a directive that could rearrange (not reorder) its child elements into a Bootstrap CSS Grid, but I am having a lot of difficulty getting access to the child elements.
I've tried a lot of different things and have researched Compile vs Link vs Controller directive options. I think I might have to change the 'compile' to 'link' in my directive to get this to work, but I am unsure how to do that.
I have an AngularJS directive on GitHub that takes an array or object of parameters to render a simple or complex grid.
In the example below you can see the layoutOptions.data = [3, 4] which means the grid will have 3 cells in the top row and 4 in the second. This is working well.
The second step is that I would like to render some divs as child elements of the directive and the directive will place these in the cells of the grid as it is created. This is shown by the layoutOptions.content = ['apple', 'orange', 'pear', 'banana', 'lime', 'lemon', 'grape'] but this needs to be de-coupled so that it could be literally anything.
HTML Input
<div ng-app="blerg">
<div ng-controller="DemoCtrl">
<div class="container" hr-layout="layoutOptions">
<div ng-transclude ng-repeat="fruit in layoutOptions.content">{{fruit}}</div>
</div>
</div>
</div>
Desired (not actual) Output
Actual output is as below, but does not include the inner DIVs with fruit names
<div class="container hr-layout" hr-layout="layoutOptions">
<div class="row">
<div class="col-md-4"><!-- from ng-repeat --><div>apple</div></div>
<div class="col-md-4"><!-- from ng-repeat --><div>orange</div></div>
<div class="col-md-4"><!-- from ng-repeat --><div>pear</div></div>
</div>
<div class="row">
<div class="col-md-3"><!-- from ng-repeat --><div>banana</div></div>
<div class="col-md-3"><!-- from ng-repeat --><div>lime</div></div>
<div class="col-md-3"><!-- from ng-repeat --><div>lemon</div></div>
<div class="col-md-3"><!-- from ng-repeat --><div>grape</div></div>
</div>
</div>
And a jsFiddle that uses it here: http://jsfiddle.net/harryhobbes/jJDZv/show/
Code
angular.module('blerg', [])
.controller('DemoCtrl', function($scope, $timeout) {
$scope.layoutOptions = {
data: [3, 4],
content: ['apple', 'orange', 'pear', 'banana', 'lime', 'lemon', 'grape']
};
})
.directive("hrLayout", [
"$compile", "$q", "$parse", "$http", function ($compile, $q, $parse, $http) {
return {
restrict: "A",
transclude: true,
compile: function(scope, element, attrs) {
//var content = element.children();
return function(scope, element, attrs) {
var contentCount = 0;
var renderTemplate = function(value, content) {
if (typeof content === 'undefined' || content.length <= contentCount)
var cellContent = 'Test content(col-'+value+')';
else if (Object.prototype.toString.call(content) === '[object Array]')
var cellContent = content[contentCount];
else
var cellContent = content;
contentCount++;
return '<div class="col-md-'+value+'">'+cellContent+'</div>';
};
var renderLayout = function(values, content) {
var renderedHTML = '';
var rowCnt = 0;
var subWidth = 0;
angular.forEach(values, function(value) {
renderedHTML += '<div class="row">';
if(Object.prototype.toString.call(value) === '[object Array]') {
angular.forEach(value, function(subvalue) {
if(typeof subvalue === 'object') {
renderedHTML += renderTemplate(
subvalue.w.substring(4), renderLayout(subvalue.d)
);
} else {
renderedHTML += renderTemplate(subvalue.substring(4));
}
});
} else {
if(value > 12) {
value = 12;
} else if (value <= 0) {
value = 1;
}
subWidth = Math.floor(12 / value);
for (var i=0; i< value-1; i++) {
renderedHTML += renderTemplate(subWidth);
}
renderedHTML += renderTemplate((12-subWidth*(value-1)));
}
renderedHTML += '</div>';
rowCnt++;
});
return renderedHTML;
};
scope.$watch(attrs.hrLayout, function(value) {
element.html(renderLayout(value.data));
});
element.addClass("hr-layout");
};
}
};
}]);
This may help - http://jsfiddle.net/PwNZ5/1/
App.directive('hrLayout', function($compile) {
return {
restrict: 'A',
// allows transclusion
transclude: true,
// transcludes the content of an element on which hr-layout was placed
template: '<div ng-transclude></div>',
compile: function(tElement, tAttrs, transcludeFn) {
return function (scope, el, tAttrs) {
var data = scope.$eval(tAttrs.hrLayout),
dom = '';
transcludeFn(scope, function cloneConnectFn(cElement) {
// hide the transcluded content
tElement.children('div[ng-transclude]').hide();
// http://ejohn.org/blog/how-javascript-timers-work/‎
window.setTimeout(function() {
for(var row = 0; row < data.data.length; row++) {
dom+= '<div class="row">';
for(var col = 0; col < data.data[row]; col++) {
dom+= '<div class="col-md-' + data.data[row] + '">' + tElement.children('div[ng-transclude]').children(':eq(' + ( row + col ) + ')').html() + '</div>';
}
dom+= '</div>';
}
tElement.after(dom);
}, 0);
});
};
}
};
});
Your approach looks like too complex. Maybe you should use ngRepeat directive http://docs.angularjs.org/api/ng.directive:ngRepeat and orderBy filter http://docs.angularjs.org/api/ng.filter:orderBy insted of updating html of element every time when hrLayout was updated?

How to make AngularJS compile the code generated by directive?

Please help me on, How can we make AngularJS compile the code generated by directive ?
You can even find the same code here, http://jsbin.com/obuqip/4/edit
HTML
<div ng-controller="myController">
{{names[0]}} {{names[1]}}
<br/> <hello-world my-username="names[0]"></hello-world>
<br/> <hello-world my-username="names[1]"></hello-world>
<br/><button ng-click="clicked()">Click Me</button>
</div>
Javascript
var components= angular.module('components', []);
components.controller("myController",
function ($scope) {
var counter = 1;
$scope.names = ["Number0","lorem","Epsum"];
$scope.clicked = function() {
$scope.names[0] = "Number" + counter++;
};
}
);
// **Here is the directive code**
components.directive('helloWorld', function() {
var directiveObj = {
link:function(scope, element, attrs) {
var strTemplate, strUserT = attrs.myUsername || "";
console.log(strUserT);
if(strUserT) {
strTemplate = "<DIV> Hello" + "{{" + strUserT +"}} </DIV>" ;
} else {
strTemplate = "<DIV>Sorry, No user to greet!</DIV>" ;
}
element.replaceWith(strTemplate);
},
restrict: 'E'
};
return directiveObj;
});
Here's a version that doesn't use a compile function nor a link function:
myApp.directive('helloWorld', function () {
return {
restrict: 'E',
replace: true,
scope: {
myUsername: '#'
},
template: '<span><div ng-show="myUsername">Hello {{myUsername}}</div>'
+ '<div ng-hide="myUsername">Sorry, No user to greet!</div></span>',
};
});
Note that the template is wrapped in a <span> because a template needs to have one root element. (Without the <span>, it would have two <div> root elements.)
The HTML needs to be modified slightly, to interpolate:
<hello-world my-username="{{names[0]}}"></hello-world>
Fiddle.
Code: http://jsbin.com/obuqip/9/edit
components.directive('helloWorld', function() {
var directiveObj = {
compile:function(element, attrs) {
var strTemplate, strUserT = attrs.myUsername || "";
console.log(strUserT);
if(strUserT) {
strTemplate = "<DIV> Hello " + "{{" + strUserT +"}} </DIV>" ;
} else {
strTemplate = "<DIV>Sorry, No user to greet!</DIV>" ;
}
element.replaceWith(strTemplate);
},
restrict: 'E'
};
return directiveObj;
});
Explanation: The same code should be used in compile function rather than linking function. AngularJS does compile the generated content of compile function.
You need to create an angular element from the template and use the $compile service
jsBin
components.directive('helloWorld', ['$compile', function(compile) {
var directiveObj = {
link: function(scope, element, attrs) {
var strTemplate, strUserT = attrs.myUsername || "";
console.log(strUserT);
if (strUserT) {
strTemplate = "<DIV> Hello" + "{{" + strUserT +"}} </DIV>" ;
} else {
strTemplate = "<DIV>Sorry, No user to greet!</DIV>" ;
}
var e = angular.element(strTemplate);
compile(e.contents())(scope);
element.replaceWith(e);
},
template: function() {
console.log(args);
return "Hello";
},
restrict: 'E'
};
return directiveObj;
}]);

Resources