Angular js directive in module not working correctly - angularjs

I have one module call "menuLeft", when module he initiate ,not loading correctly my directive, but if run my function en el method "run" correctly.
I dont know why is this.
This is my code
(function () {
angular.module('menuLeft', []);
angular.module('menuLeft')
.run(htmlMenuDirectivaGrupo)
.directive('ctrlMenuDirectivaGrupo', ctrlMenuDirectivaGrupo);
//MY MENU DIRECTIVE (THIS NOT LOAD)
//MENU GRUPO
/**
* #ngInject
*/
function ctrlMenuDirectivaGrupo($timeout) {
alert('hello ctrlmenu');
return {
scope: {
section: '='
},
templateUrl: 'partials/menuToogle.tmpl.html',
link: function ($scope, $element) {
var controller = $element.parent().controller();
$scope.isOpen = function () {
return controller.isOpen($scope.section);
};
$scope.toggle = function () {
controller.toggleOpen($scope.section);
};
}
};
}
//MY TEMPLATE FOR DIRECTIVE (THIS IF LOAD)
/**
* #ngInject
*/
function htmlMenuDirectivaGrupo($templateCache) {
alert('hello htmlmenu');
$templateCache.put('partials/menuToogle.tmpl.html',
'<md-button class="md-button-toggle"\n' +
' ng-click="toggle()"\n' +
' aria-controls="docs-menu-{{section.name | nospace}}"\n' +
' flex layout="row"\n' +
' aria-expanded="{{isOpen()}}">\n' +
' {{section.name}}\n' +
' <span aria-hidden="true" class=" pull-right fa fa-chevron-down md-toggle-icon"\n' +
' ng-class="{\'toggled\' : isOpen()}"></span>\n' +
'</md-button>\n' +
'<ul ng-show="isOpen()" id="docs-menu-{{section.name | nospace}}" class="menu-toggle-list">\n' +
' <li ng-repeat="page in section.pages">\n' +
' <menu-link section="page"></menu-link>\n' +
' </li>\n' +
'</ul>\n' +
'');
}
})();
Why not load two functions?, there are bad code or declarations?
thanks.

Use something like this . .
return {
restrict: 'E',
scope: {
section: '='
},
controller: ['$scope', function ($scope){..}],
link: function (scope, element, attrs) {..},
template: '<div class="bootsrtap">'+
'<input type="text" ng-model="searchParam" placeholder="{{ attrs.placeholder }}"'+
'class="{{ attrs.inputclass }}"'+
'id="{{ attrs.inputid }}"'+
'ng-required="{{ autocompleteRequired }}" />'+
'</div> '
};

the problem is , what my directive nor declaring correctly in .html
This is the way we should call it to function properly.
DIRECTIVES
(function () {
angular.module('menuLeft', []);
angular.module('menuLeft')
.run(htmlMenuDirectivaGrupo)
.directive('menuGrupo', ctrlMenuDirectivaGrupo);
//MY MENU DIRECTIVE (THIS NOT LOAD)
//MENU GRUPO
/**
* #ngInject
*/
function ctrlMenuDirectivaGrupo($timeout) {
alert('hello ctrlmenu');
return {
scope: {
section: '='
},
templateUrl: 'partials/menuToogle.tmpl.html',
link: function ($scope, $element) {
var controller = $element.parent().controller();
$scope.isOpen = function () {
return controller.isOpen($scope.section);
};
$scope.toggle = function () {
controller.toggleOpen($scope.section);
};
}
};
}
//MY TEMPLATE FOR DIRECTIVE (THIS IF LOAD)
/**
* #ngInject
*/
function htmlMenuDirectivaGrupo($templateCache) {
alert('hello htmlmenu');
$templateCache.put('partials/menuToogle.tmpl.html',
'<md-button class="md-button-toggle"\n' +
' ng-click="toggle()"\n' +
' aria-controls="docs-menu-{{section.name | nospace}}"\n' +
' flex layout="row"\n' +
' aria-expanded="{{isOpen()}}">\n' +
' {{section.name}}\n' +
' <span aria-hidden="true" class=" pull-right fa fa-chevron-down md-toggle-icon"\n' +
' ng-class="{\'toggled\' : isOpen()}"></span>\n' +
'</md-button>\n' +
'<ul ng-show="isOpen()" id="docs-menu-{{section.name | nospace}}" class="menu-toggle-list">\n' +
' <li ng-repeat="page in section.pages">\n' +
' <menu-link section="page"></menu-link>\n' +
' </li>\n' +
'</ul>\n' +
'');
}
})();
HTML
<menu-grupo></menu-grupo>
I recommend reading https://github.com/johnpapa/angular-styleguide
Thanks for all.

Related

AngularJS ng-click doesn't fire

I generate some a Tags dynamically from a json file and add them like this to the page:
for(var i = 0; i < currentScene.hotpoints.hotpoint.length; i++)
{
var hotpoint = currentScene.hotpoints.hotpoint[i];
var pos = hotpoint.pos.split(";");
var x = parseFloat(pos[0]) * multiplierX;
var y = parseFloat(pos[1]) * multiplierY;
htmlstring += '<a href ng-controller="main" id="hp'+ hotpoint.ID + '" class="hotpoint animated infinite" style="top: ' + parseInt(y) + 'px; left: ' + parseInt(x) + 'px;" ng-click="enterScene(' +hotpoint.sceneID + ',' + hotpoint.ID +')"></a>';
}
$scope.hotpoints = $sce.trustAsHtml(htmlstring);
That works great. Now like you see I want to enable the click event for each element. So I use ng-click. But it doesn't get fired.
When I add this ng-click to an "static" element which is already on the site everything works.
What I have to care about that this works?
Thanks
Yes... $compile shall be used for this..
(function(){
"use strict";
angular.module("CompileDirective", [])
.directive('dynamicElement', ['$compile', function ($compile) {
return {
restrict: 'E',
scope: {
message: "="
},
replace: true,
link: function(scope, element, attrs) {
var template = $compile(scope.message)(scope);
element.replaceWith(template);
},
controller: ['$scope', function($scope) {
$scope.clickMe = function(){
alert("hi")
};
}]
}
}])
.controller("DemoController", ["$scope", function($scope){
$scope.htmlString = '<div><input type="button" ng-click="clickMe()" value="click me!"/> </div>';
}])
}());
With the following HTML:
<div ng-controller="DemoController">
<dynamic-element message='htmlString'></dynamic-element>
</div>
OR you may also go for injecting $compile in controller..
app.controller('AppController', function ($scope, $compile) {
var $el = $('<td contenteditable><input type="text" class="editBox" value=""/></td>' +
'<td contenteditable><input type="text" class="editBox" value=""/></td>' +
'<td>' +
'<span>' +
'<button id="createHost" class="btn btn-mini btn-success" data-ng-click="create()"><b>Create</b></button>' +
'</span>' +
'</td>').appendTo('#newTransaction');
$compile($el)($scope);
$scope.create = function(){
console.log('clicked')
}
})
And the easiest way..
$("#dynamicContent").html(
$compile(
"<button ng-click='count = count + 1' ng-init='count=0'>Increment</button><span>count: {{count}} </span>"
)(scope)
);

Generating html directive

I am creating a directive that will generate the HTML elements automatically according to data that received from the server.
Here is angularjs code:
(function () {
"use strict";
angular.module("workPlan").directive("myGenericFilter", ["$compile", "$http", "config", myGenericFilterData]);
function myGenericFilterData($compile, $http, config) {
var directive = {
restrict: "E",
scope: {
filterParams: "=filterparameters",
},
//templateUrl: config.baseUrl + "app/workPlan/templates/workPlanList.tmpl.html",
template: '<div></div>',
controller: "genericFilterDataController",
controllerAs: "filter",
link: function (scope, element) {
var parameters;
var el = angular.element('<span/>');
$http.post(config.baseUrl + "api/FilterConfigurations/", scope.filterParams).then(function (result) {
parameters = result.data;
angular.forEach(parameters, function (parameter, key) {
switch (parameter.ValueType) {
case 'Int32':
el.append('<div class="form-group">' +
'<div class="">' +
'<span class="view"></span>' +
'<input type="text"' + 'id =' + parameter.ObjectName + ' class="form-control">' +
'</div>' +
'</div>');
break;
case 'DateTime':
el.append('<div class="form-group">' +
'<span class="view"></span>' +
'<my-datepicker placeholder="dd/mm/yyyy" class=""></my-datepicker>' +
'</div>');
break;
}
});
});
$compile(el)(scope);
element.append(el);
}
}
return directive;
}
})();
As you can see I get data from server and according to parameter.ValueType appropriate case selected in the switch.
After the angular.forEach operator iterated on all items in the parameters variable and all DOM elements is loaded, all input HTML elements displayed except my-datepicker custom directive.
When I use F12 to Inspect Element I see the HTML code of all the elements(include my-datepicker).
Here how it's looks:
But in the view my-datepicker not displayed, here how it looks in view:
my-datepicker is custom directive that defined in common module that injected in all moduls in my project.
Any idea why my-datepicker not displayed in the view?
You compile el before the content of el is setted.
Remember that $http request is async then put
$compile(el)(scope);
element.append(el);
Into the callback
link: function (scope, element) {
var parameters;
var el = angular.element('<span/>');
$http.post(config.baseUrl + "api/FilterConfigurations/", scope.filterParams).then(function (result) {
parameters = result.data;
angular.forEach(parameters, function (parameter, key) {
switch (parameter.ValueType) {
case 'Int32':
el.append('<div class="form-group">' +
'<div class="">' +
'<span class="view"></span>' +
'<input type="text"' + 'id =' + parameter.ObjectName + ' class="form-control">' +
'</div>' +
'</div>');
break;
case 'DateTime':
el.append('<div class="form-group">' +
'<span class="view"></span>' +
'<my-datepicker placeholder="dd/mm/yyyy" class=""></my-datepicker>' +
'</div>');
break;
}
});
$compile(el)(scope);
element.append(el);
});
}

ngMessages dont work inside a directives template

My ngMessages doesnt work inside my directives template!
I have a directive myInput with a template and a link function, inside the template function I create template string for a wrapped <label> and <input>.
Inside the Link function I use the require: '^form' FormController and retrieve the form name. Then I'm putting a ngMessages block after the wrapped elements.
(function () {
'use strict';
angular
.module('app.components')
.directive('myInput', MyInput);
/*#ngInject*/
function MyInput($compile, ValidatorService, _, LIST_OF_VALIDATORS) {
return {
require: '^form',
restrict: 'E',
controller: MyInputController,
controllerAs: 'vm',
bindToController: true,
template: TemplateFunction,
scope: {
label: '#',
id: '#',
value: '=',
validateCustom: '&'
},
link: MyInputLink
};
function MyInputController($attrs) {
var vm = this;
vm.value = '';
vm.validateClass = '';
vm.successMessage = '';
vm.errorMessage = '';
}
function TemplateFunction(tElement, tAttrs) {
return '<div class="input-field">' +
' <label id="input_{{vm.id}}_label" for="input_{{vm.id}}" >{{vm.label}}</label>' +
' <input id="input_{{vm.id}}" name="{{vm.id}}" ng-class="vm.validateClass" type="text" ng-model="vm.value" >' +
'</div>';
}
function MyInputLink(scope, element, attrs, form){
var extra = ' <div ng-messages="' + form.$name + '.' + scope.vm.id + '.$error">' +
' <div ng-messages-include="/modules/components/validationMessages.html"></div>' +
' </div>';
$(element).after(extra);
}
}
})();
Usage:
<h1>Test</h1>
<form name="myForm">
<my-input label="My Input" id="input1" value="vm.input1"></my-input>
-------
<!-- this block is hardcoded and is working, it does not come from the directive! -->
<div ng-messages="myForm.input1.$error">
<div ng-messages-include="/modules/components/validationMessages.html"></div>
</div>
</form>
Instead of adding the ngMessages block inside the link function, add it inside the compile function.
It is not as handy as in the link funciton because of the missing FormController, but it works :-)
Here the code:
compile: function(tElement, tAttrs){
var name = tElement.closest('form').attr('name'),
fullFieldName = name + '.' + tAttrs.id; // or tAttrs.name
var extra = '<div ng-messages="' + fullFieldName + '.$error">' +
' <div ng-messages-include="/modules/components/validationMessages.html"></div>' +
'</div>';
$(element).after(extra);
Here is what I did, I added to scope, myForm: '=' then in the directive's template referred to <div ng-messages="vm.myForm[vm.id].$error" >
I feel this is much cleaner than mucking around in the link function.

How to pass multiple attribute in AngularJS directive

How to pass multiple attribute to a directive.
How to pass value 12 of click-to-edit1 inside below div like
<div click-to-edit="location.state" click-to-edit1=12></div>
and should be accessible in directive controller.please help me out.
Code:
App HTML:
<div ng-controller="LocationFormCtrl">
<h2>Editors</h2>
<div class="field">
<strong>State:</strong>
<div click-to-edit="location.state"></div>
</div>
<h2>Values</h2>
<p><strong>State:</strong> {{location.state}}</p>
</div>
App directive:
app = angular.module("formDemo", []);
app.directive("clickToEdit", function() {
var editorTemplate = '<div class="click-to-edit">' +
'<div ng-hide="view.editorEnabled">' +
'{{value}} ' +
'<a ng-click="enableEditor()">Edit</a>' +
'</div>' +
'<div ng-show="view.editorEnabled">' +
'<input ng-model="view.editableValue">' +
'Save' +
' or ' +
'<a ng-click="disableEditor()">cancel</a>.' +
'</div>' +
'</div>';
return {
restrict: "A",
replace: true,
template: editorTemplate,
scope: {
value: "=clickToEdit",
},
controller: function($scope) {
$scope.view = {
editableValue: $scope.value,
editorEnabled: false
};
$scope.enableEditor = function() {
$scope.view.editorEnabled = true;
$scope.view.editableValue = $scope.value;
};
$scope.disableEditor = function() {
$scope.view.editorEnabled = false;
};
$scope.save = function() {
$scope.value = $scope.view.editableValue;
$scope.disableEditor();
};
}
};
});
App controller:
app.controller("LocationFormCtrl", function($scope) {
$scope.location = {
state: "California",
};
});
Add new property inside directives scope:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.location = {
state: "California",
};
});
app.directive("clickToEdit", function() {
var editorTemplate = '<div class="click-to-edit">' +
'<div ng-hide="view.editorEnabled">' +
' {{value}} ' +
'<a ng-click="enableEditor()">Edit</a>' +
'</div>' +
'<div>{{value1}}</div>' +
'<div ng-show="view.editorEnabled">' +
'<input ng-model="view.editableValue">' +
'Save' +
' or ' +
'<a ng-click="disableEditor()">cancel</a>.' +
'</div>' +
'</div>';
return {
restrict: "A",
replace: true,
template: editorTemplate,
scope: {
value: "=clickToEdit",
value1: "=clickToEdit1"
},
controller: function($scope) {
$scope.view = {
editableValue: $scope.value,
editorEnabled: false
};
$scope.enableEditor = function() {
$scope.view.editorEnabled = true;
$scope.view.editableValue = $scope.value;
};
$scope.disableEditor = function() {
$scope.view.editorEnabled = false;
};
$scope.save = function() {
$scope.value = $scope.view.editableValue;
$scope.disableEditor();
};
}
};
});
html:
<div class="field">
<strong>State:</strong>
<div click-to-edit="location.state" click-to-edit1="12"></div>
</div>
working example: http://plnkr.co/edit/e7oTtZNvLdu6w5dgFtfe?p=preview
you first tell the div that you want your directive on it.
<div click-to-edit value='location.state' value1='12'></div>
app.directive("clickToEdit", function() {
return {
restrict: "A",
scope : {
value : "=",
value1 : "="
},
link : function($scope) {
console.log("the first value, should be location.state value on the controller", $scope.value);
console.log("the second value, should be '12'", $scope.value);
}
}
it might seem more logic when you use the directive as a element.
but bottom line is that the diretive looks for attributes on the element, which you then can attach to the directive via the scope. '=' for two way binding, '#' for one way.

How to use compile function in AngularJS directive to ng-repeat elements from a service

Could someone, please, show me what I need to do to render in a directive new elements stored in an array in a service. In the example below, an alert from the service shows that each new element is added to the elements array, but how to make the directive show these new elements on the page?
I tried to read everything about compile function in a directive, but could not understand how to make my example work.
Here is a jsfiddle. All I need is to render new messages inside the directive after they are added to the message array in the service.
The Chat service is injected into directive as a chat variable, and in the directive template I want to repeat every message from the service:
'<ul>' +
'<li ng-repeat="message in chat.messages">' +
'<strong>{{message.name}}</strong> {{message.text}}' +
'</li>' +
'</ul>'
Sample code is on jsfiddle and below:
HTML:
<div ng-app="myApp">
<my-simple-chat title="AngularJS Chat"></my-simple-chat>
</div>
JavaScript:
angular.module('myApp', [])
.factory('Chat', function () {
var messages = [];
function sendMessage(name, text) {
messages.push(
{
name: name,
text: text
});
alert("Sending message from factory: " + name + ", " + text + " : " + messages.length);
};
return {
messages: messages,
sendMessage: sendMessage
};
})
.directive('mySimpleChat', ['Chat', function (chat) {
var tmpl = '<div><h2>{{title}}</h2>' +
'<input type="text" ng-model="name" placeholder="Type your name"/>' +
'<hr />' +
'<form ng-submit="sendMessage()">' +
'<input type="text" ng-model="text" required placeholder="Type a new message..."/>' +
'<input type="submit" id="submit" value="Send"/>' +
'</form>' +
'<ul>' +
'<li ng-repeat="message in chat.messages">' +
'<strong>{{message.name}}</strong> {{message.text}}' +
'</li>' +
'</ul>' +
'<div>';
return {
restrict: 'E',
replace: true,
scope: { title: '#title' },
template: tmpl,
controller: ['$scope', '$element', '$attrs', '$transclude',
function ($scope, $element, $attrs, $transclude) {
$scope.name = 'MyName';
$scope.text = '';
$scope.sendMessage = function () {
chat.sendMessage($scope.name, $scope.text);
$scope.text = '';
};
}],
};
}]);
You are using ngRepeat on chat.messages but never assigning chat to be part of $scope.
controller: ['$scope', '$element', '$attrs', '$transclude',
function ($scope, $element, $attrs, $transclude) {
$scope.name = 'MyName';
$scope.text = '';
$scope.chat = chat; //<--this so you can use ngRepeat
$scope.sendMessage = function () {
chat.sendMessage($scope.name, $scope.text);
$scope.text = '';
};
}],
updated fiddle.
Looks like writing a question on SO is 90% way to its answer... All I needed to do was to add a link function to the directive:
link: function ($scope, element, attributes) {
$scope.messages = chat.messages;
}
and remove chat. from ng.repeat:
'<ul>' +
'<li ng-repeat="message in messages">' +
'<strong>{{message.name}}</strong> {{message.text}}' +
'</li>' +
'</ul>'
I am not sure that this is the right way to do the task, but it just works. In docs I have read that I have to use compile function if I use ng-repeat in a template, so I am still confused somewhat.
An updated jsfiddle.
You can create a bridge like this:
<li ng-repeat="message in messages()">
$scope.messages = function () {
return chat.messages;
}

Resources