ng-switch and manually $compile - angularjs

I tried to make recursive directive like here
Angularjs: understanding a recursive directive
ng-switch options are all commented, ng-if works fine.
I don't know what is a problem.
Just inspect output of ng-switch
var module = angular.module('myapp', []);
module.controller("TreeCtrl", function($scope) {
$scope.controls = [
{
"label":"Checkbox",
"type":"checkbox"
},
{
"label":"input",
"type":"input"
},
{
"label":"Some group",
"type":"Group",
"controls":[
{
"label":"subcontrol",
"type":"input"
}
]
}
];
});
module.directive("tree", function($compile) {
return {
restrict: "E",
scope: {controls: '='},
template:
'<div ng-switch="control.type">' +
'<label>{{control.label}}</label>'+
'<div ng-switch-when="input"><input type="text" name="ctrl1"></input></div>'+
'<div ng-switch-when="checkbox"><input type="checkbox" "name="ctr2"></input></div>'+
'<div ng-repeat="subcontrol in control.controls">' +
'<tree control="subcontrol"></tree>' +
'</div>' +
'</div>',
compile: function(tElement, tAttr, transclude) {
//We are removing the contents/innerHTML from the element we are going to be applying the
//directive to and saving it to adding it below to the $compile call as the template
var contents = tElement.contents().remove();
var compiledContents;
return function(scope, iElement, iAttr) {
if(!compiledContents) {
compiledContents = $compile(contents, transclude);
}
compiledContents(scope, function(clone, scope) {
iElement.append(clone);
});
};
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myapp">
<div ng-controller="TreeCtrl">
<div ng-repeat='control in controls'>
<tree control="control"></tree>
</div>
</div>
</div>

Related

Error: [$compile:ctreq] data passing between two directive from different module

I have two different module in which I have two directives. I need to pass data between these two directive. I use require property. but I get some error
Error: [$compile:ctreq] Controller 'yearSort', required by directive 'budgetSort', can't be found!
My first directive is
angular.module('movieApp.yearsort.directives', []).directive('yearSort',[function(){
return{
restrict : 'AEC',
replace : true,
transclude : true,
controller : 'YearsortController',
templateUrl : 'app/components/yearsort/yearsort.html',
};
}]);
In the YearsortController I have the code
angular.module('movieApp.yearsort.controller', []).controller('YearsortController', ['$scope','HomeFactory','$timeout','$state',function($scope,HomeFactory,$timeout,$state) {
this.sayHello = function() {
$scope.words = "my requier";
console.log( $scope.words);
};
}]);
In my second directive I have the code
angular.module('movieApp.budgetsort.directives', []).directive('budgetSort',[function(){
return{
restrict : 'AEC',
replace : true,
transclude : true,
controller : 'BudgetsortController',
templateUrl : 'app/components/budgetSort/budgetSort.html',
require : "yearSort",
link : function(scope,element, attrs, demoCtrl){
demoCtrl.sayHello();
}
};
}]);
Why don't you try using a Service/Factory? It is a good option when you need to pass data through components or directives
I've made this plunkr to explain: http://plnkr.co/edit/V7BLbOrrtNhXl1QlUKxA?p=preview
HTML:
<body ng-controller="myCtrl">
<first-directive></first-directive>
<second-directive></second-directive>
</body>
Javascript:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, dataService) {
$scope.name = 'World';
//set up the items.
angular.copy([ { name: 'test'} , { name: 'foo' } ], dataService.items);
});
app.directive('firstDirective', function(dataService){
return {
restrict: 'E',
template: '<h3>Directive 1</h3>' +
'<div ng-repeat="item in data.items">' +
'<input type="text" ng-model="item.name"/>' +
'</div>',
link: function(scope, elem, attr) {
scope.data = dataService;
}
};
});
app.directive('secondDirective', function(dataService){
return {
restrict: 'E',
template: '<h3>Directive 2</h3>' +
'<div ng-repeat="item in data.items">' +
'<input type="text" ng-model="item.name"/>' +
'</div>',
link: function(scope, elem, attr) {
scope.data = dataService;
}
};
});
app.factory('dataService', [function(){
return { items: [] };
}]);
The Demo
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, dataService) {
$scope.name = 'World';
//set up the items.
angular.copy([ { name: 'test'} , { name: 'foo' } ], dataService.items);
});
app.directive('firstDirective', function(dataService){
return {
restrict: 'E',
template: '<h3>Directive 1</h3>' +
'<div ng-repeat="item in data.items">' +
'<input type="text" ng-model="item.name"/>' +
'</div>',
link: function(scope, elem, attr) {
scope.data = dataService;
}
};
});
app.directive('secondDirective', function(dataService){
return {
restrict: 'E',
template: '<h3>Directive 2</h3>' +
'<div ng-repeat="item in data.items">' +
'<input type="text" ng-model="item.name"/>' +
'</div>',
link: function(scope, elem, attr) {
scope.data = dataService;
}
};
});
app.factory('dataService', [function(){
return { items: [] };
}]);
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="myApp" ng-controller="myCtrl">
<first-directive></first-directive>
<second-directive></second-directive>
</body>

Send data from controller to directive

I want to send that to my directive but I want that data to stay updated if the data in the controller changes.
// Controller
angular
.module('app')
.controller('IndexController', IndexController)
IndexController.$inject = [];
function IndexController() {
var vm = this;
vm.name = 'John';
newName = function() {
vm.name = 'Brian';
}
newName();
}
// Directive
angular
.module('app')
.directive('userName', userName);
userName.$inject = ['$document'];
function userName($document) {
var directive = {
restrict: 'EA',
template: '<div id="user"></div>',
replace: true,
scope: {
name: '='
},
link: function(scope, elem, attrs) {
console.log(scope.data);
}
}
return directive;
}
this is how I use the directive. the problem is that it always returns the first name and not the new name after the change in the controller.
<div ng-controller="indexController">
<user-name name="indexController.name">
</div>
thank you.
Try this, you just have to inject $scope into your Indexcontroller
angular
.module('app', [])
.controller('IndexController', function($scope) {
var vm = this;
vm.name = 'John';
vm.newName = function() {
vm.name = 'Brian';
console.log(vm.name);
}
//vm.newName();
})
.directive('userName', ['$document', function() {
var directive = {
restrict: 'E',
template: '<div id="user"></div>',
replace: true,
scope: {
name: '='
},
link: function(scope, elem, attrs) {
console.log(scope.name);
}
}
return directive;
}])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="IndexController as vm">
<user-name name="vm.name"></user-name>
<button ng-click="vm.newName()">Click</button>
</div>
Without using as in controller, you cannot use controller.prop inside the scope.
Inside the controlleryou need to call the method using its $scope or this.
Check the below code.
angular
.module('app', [])
.controller('IndexController', function($scope) {
$scope.name = 'John';
$scope.newName = function() {
$scope.name = 'Brian';
}
$scope.newName();
})
.directive('userName', ['$document', function() {
var directive = {
restrict: 'E',
template: '<div id="user"></div>',
replace: true,
scope: {
name: '='
},
link: function(scope, elem, attrs) {
console.log(scope.name);
}
}
return directive;
}])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="IndexController">
<user-name name="name"></user-name>
</div>

AngularJS: ng-click not working in custom input directive

I'm new in AngularJS, currently I'm working on custom input directive with a label.
I refer to one article in stack overflow but encountered problem.
The running code is on fiddle:
http://jsfiddle.net/luneyq/bpN9b/18/
Core code is as below:
<!doctype html>
<html>
<head>
<script src="../common/angular.js"></script>
</head>
<body>
<div ng-app="myApp">
<div ng-controller="MainController">
<my-input type="number" name="valueNumber1" ng-model="valueNumber1" label="Age" ng-change="change()" ng-click="click()"></my-input>
<div id="result">a</div>
</div>
</div>
<script>
var app = angular.module("myApp", []);
app.controller('MainController', function($scope, $window){
$scope.valueNumber1 = 10;
$scope.change = function() {
document.getElementById("result").innerHTML = 'change:' + $scope.valueNumber1;
};
$scope.click = function() {
document.getElementById("result").innerHTML = 'click:' + $scope.valueNumber1;
};
});
app.directive('myInput', function() {
return {
require: '^ngModel',
restrict: 'EA',
scope: {
ngModel: '=',
name: '#name',
label: '#label'
},
replace: true,
transclude: true,
//priority: 10,
template: '<div>' +
'<label for="{{ name }}">{{label}}</label>' +
'<input id="{{ name }}" ng-model="ngModel" />' +
'</div>',
compile: function(tElement, tAttrs, transclude) {
var tInput = tElement.find('input');
// Move the attributed given to 'custom-input' to the real input field
angular.forEach(tAttrs, function(value, key) {
if (key.charAt(0) == '$' || key == "class")
return;
tInput.attr(key, value);
tInput.parent().removeAttr(key);
});
tElement.removeAttr('ng-model');
return;
}
};
})
</script>
</body>
</html>
My problems are:
1. ng-click and ng-change not working on the input
2. ng-model="ngModel" on input element, why ngModel is used here? if I change ngModel to aaa, the initial value for the input disappeared
3. attributes copy in compile function removed the dash(-) signal, ng-click is copied as ngClick.
I'm not sure is this the cause of this problem.
Can anyone help on this problem?
Your problem was click and change methods not in your isolate scope - BUT you are not making use of Angular's two way binding here - instead simply use ng-bind on your result div - here's a fiddle http://jsfiddle.net/bpN9b/20/
var app = angular.module("myApp", []);
app.controller('MainController', function($scope, $window){
$scope.valueNumber1 = 10;
});
app.directive('myInput', function() {
return {
require: '^ngModel',
restrict: 'EA',
scope: {
ngModel: '=',
name: '#name',
label: '#label'
},
replace: true,
priority: 10,
template: '<div class="cbay-input-div">' +
'<label for="{{ name }}">{{label}}</label>' +
'<input id="{{ name }}" ng-model="ngModel" />' +
'</div>',
compile: function(tElement, tAttrs, transclude) {
console.log(tAttrs);
var tInput = tElement.find('input');
// Move the attributed given to 'custom-input' to the real input field
angular.forEach(tAttrs, function(value, key) {
//console.log(key + " = " + value);
if (key.charAt(0) == '$' || key == "class")
return;
tInput.attr(key, value);
tInput.parent().removeAttr(key);
});
tElement.removeAttr('ng-model');
return;
}
};
});
here's the template
<div ng-app="myApp">
<div ng-controller="MainController">
<my-input type="number" name="valueNumber1" ng-model="valueNumber1" label="Age" ng-change="change(this)" ng-click="click(this)"></my-input>
<div id="result" ng-bind="valueNumber1">a</div>
</div>
</div>

AngularJS How to parse html into directive template

How i can parse html in directive template???
app.directive('user', function(){
return {
restrict: 'E',
scope: false,
template: '<div class="clearfix buttons-container" ng-bind-html-unsafe="current_text"></div>'
}
});
//in controller
$scope.current_text = 'Hello <strong>'+current_username+'</strong> !!!'
use $sce.trustAsHtml. this method will create trusted HTML object for ng-bind-html directive.
$sce.trustAsHtml Docs
See below example
var app = angular.module('app', []);
app.controller('ctrl', function($scope, $sce) {
var current_username = "User";
var html = 'Hello <strong>' + current_username + '</strong> !!!';
$scope.current_text = $sce.trustAsHtml(html);
});
app.directive('user', function() {
return {
restrict: 'E',
scope: false,
template: '<div class="clearfix buttons-container" ng-bind-html="current_text"></div>'
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="ctrl">
<user></user>
</div>
</div>
you can do this using isolate-scope
in this way.
app.directive('user', function(){
return {
restrict: 'E',
scope: {
current_text : '#current_text'
},
template: '<div class="clearfix buttons-container" ng-bind-html-unsafe="current_text"></div>'
}
});
//in controller
$scope.currenText = 'Hello <strong>'+current_username+'</strong> !!!'
<div current_text="currenText" > </div> // your directive included here

how to call parent method from directive?

I have directive like this
.directive('myModal', function() {
return {
restrict: 'A',
replace: true,
scope: {
myModalId: '#'
},
template: '<div id="{{myModalId}}" class="modal">' +
'<div ng-click="parentMethod()" class="modal-dialog">' +
'...' +
'</div>' +
'</div>'
}
});
js code
function ParentController($scope) {
$scope.parentMethod = function() {
alert('clicked');
}
}
There are several ways you can achieve this. I would do it using attribute binding which allows you to execute an expression in the context of the parent scope. This is how you can use it:
<div my-modal my-modal-id="12312" on-click="parentMethod()"></div>
Then in directive you define scope like this:
scope: {
myModalId: '#',
onClick: '&'
}
and in directive template:
<div ng-click="onClick()" class="modal-dialog">
Demo: http://plnkr.co/edit/UDnJGRVqXqbCGSFEAMMA?p=preview
Another way (not recommended), you can directly refer the parent scope from isolated directive scope:
<div ng-click="$parent.parentMethod()" class="modal-dialog">
<body ng-app="myApp">
<div ng-controller="myCtrl">
<direct movied="movie" call-home="callFromDirect"></direct>
</div>
<script>
var myApp = angular.module("myApp", []);
myApp.controller("myCtrl", function($scope, $rootScope) {
$scope.callFromDirect = function (param) {
console.log('got call to direct ' + param);
}
});
myApp.directive("direct", function () {
return {
restrict: 'E',
scope: {
callHome: '='
},
template: "<input type=\"button\" value=\"click\" ng-click=\"callHome('movie')\" />"
}
});
</script>

Resources