In this directive I'm attempting to display the result of multiple get requests :
plnkr : https://plnkr.co/edit/BjETLN7rvQ1hNRIm51zG?p=preview
src :
http-hello1.html :
{ "content" : "divContent" , "id" : "r1" }
http-hello2.html :
2. http-hello2.html
http-hello3.html :
3. http-hello3.html
index.html :
<!doctype html>
<html ng-app>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body>
<div ng-controller="FetchCtrl">
<source-viewer ng-repeat="sourceUrl in sourceUrls" url="sourceUrl"></source-viewer>
</div>
</body>
</html>
mytemplate.html :
<h1>{{url}}</h1>
<div>
<p>{{model.address}}</p>
</div>
script.js :
// Example of how to call AngularJS $http service and
var myapp = angular.module('app', []).controller('FetchCtrl', FetchCtrl)
myapp.directive('sourceViewer', function ($http) {
return {
restrict: 'E',
templateUrl: 'mytemplate.html',
scope: {
url: '='
},
link: function (scope, elem, attrs, ctrl) {
$http.get(scope.url).success(function (data) {
$scope.model = data.data;
});
}
};
});
function FetchCtrl($scope, $http, $q , $parse) {
$scope.sourceUrls = [
'http-hello1.html',
'http-hello2.html',
'http-hello3.html'
];
}
But nothing is being rendered. Am I defining the directive correctly ?
Use ng-include in mytemplate.html
https://plnkr.co/edit/gPoRn89anqn7uLRMYVSG?p=preview
Related
I have two directives, parent directive should simply wrap around its child. The transclusion is used for this purpose.
However, then any other directive, such as ng-click, bound to the child directive element as its attribute does not work (is it not compiled?).
Here is the JS:
(function(angular) {
'use strict';
angular.module('docsIsoFnBindExample', [])
.controller('Controller', ['$scope', '$timeout', function($scope, $timeout) {
$scope.name = 'Tobias';
$scope.message = '';
$scope.hideDialog = function(message) {
$scope.message = message;
$scope.dialogIsHidden = true;
$timeout(function() {
$scope.message = '';
$scope.dialogIsHidden = false;
}, 2000);
};
}]) //controller is not important now
.directive('myDialog', function() { //parent directive
return {
restrict: 'E',
transclude: true,
scope: {
'close': '&onClose'
},
template: '<div class="alert"><a href class="close" ng-click="close({message: \'closing for now\'})">×</a><div ng-transclude></div></div>'
};
})
.directive('daka', function() { //child directive
return {
restrict: 'E',
scope: {
'input': '#'
},
link: function(scope, element, attributes) {
scope.func= function() {
console.log("blablabla"); //no console output after click event
};
}
};
});
})(window.angular);
HTML:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-directive-transclusion-scope-production</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="docsIsoFnBindExample">
<div ng-controller="Controller">
{{message}}
<my-dialog ng-hide="dialogIsHidden" on-close="hideDialog(message)">
<daka ng-click="func()" input="11">BLABlABLA</daka>
</my-dialog>
</div>
</body>
</html>
It is trying to look ng-click in your parent directive.
So you can add click event for your child directive.
.directive('daka', function() { //child directive
return {
restrict: 'E',
scope: {
'input': '#'
},
link: function(scope, element, attributes) {
element.on('click', function() {
alert('outcome clicked: ');
});
}
}; });
working jsfiddle link -https://jsfiddle.net/p2vht8sb/
This code is invoking multiple get requests and updating model
from result of each get request.
http.get is asynchronous, does this extend to when the UI model is updated ?that if the get request returns data out of order (the 3'rd get request returns data before the 1'st request) then the third value for statusViewer directive
will be updated first on UI ? If not how can modify to update UI model when data is returned from get request ?
plnkr :
https://plnkr.co/edit/BjETLN7rvQ1hNRIm51zG?p=preview
plnkr src :
http-hello1.html:
{ "content" : "divContent" , "id" : "r1" }
http-hello2.html:
2. http-hello2.html
http-hello3.html:
3. http-hello3.html
index.html :
<!doctype html>
<html ng-app="app">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body>
<div ng-controller="FetchCtrl">
<status-viewer ng-repeat="sourceUrl in sourceUrls" url="sourceUrl"></status-viewer>
</div>
</body>
</html>
mytemplate.html:
<!--<h1>{{url}}</h1>-->
<div>
<p>{{model}}</p>
</div>
script.js :
var myapp = angular.module('app', []).controller('FetchCtrl', FetchCtrl)
myapp.directive('statusViewer', function ($http) {
return {
restrict: 'E',
templateUrl: 'mytemplate.html',
scope: {
url: '='
},
link: function (scope, elem, attrs, ctrl) {
$http.get(scope.url).success(function (data) {
scope.model = JSON.stringify(data);
});
}
};
});
function FetchCtrl($scope, $http, $q , $parse) {
$scope.sourceUrls = [
'http-hello1.html',
'http-hello2.html',
'http-hello3.html'
];
}
Update : The expected behavior is that the UI model will be updated in same order as 'success' callback is invoked, is my expected behavior assertion valid ?
I am trying to use two directives inside a directive, however the last directive is compiled but the content still has it's curly braces.It is a lazy loading directive, that happens when i click on a image. Any idea why this happens? Here is the demo: demo on plnker
(function (angular) {
angular.module("app", []).directive("expandingGrid", [
"$http", function($window) {
return {
restrict: "E",
templateUrl:"grid.tmpl.html",
controller: [
"$scope", "$http", "$attrs", function($scope, $http, $attrs) {
var self = this;
$scope.items = [];
var $element = $attrs.$$element;
$scope.items = [{title:"Emanuel", desciption:"taking a test"}];
} ]
}
}
]).directive("gridItem", [
"$timeout", "$compile", function($timeout, $compile) {
return {
transclude:true,
restrict: "EA",
require: "^expandingGrid",
templateUrl: "gridItem.tmpl.html",
controller: [
"$scope", "$http", "$attrs", function ($scope, $http, $attrs) {
}
],
link: function(scope, element, attrs) {
element.on("click", function(event) {
scope.preview = {name:"emanuel", title:"detailed description"};
var $html = $("<div preview-item scope='preview'></div>");
var el=$compile($html)(scope);
element.append(el);
});
}
}
}
]).directive("previewItem", [
function() {
return {
transclude: true,
scope:false,
restrict: "EA",
template: "{{preview.title}}",
controller:["$scope", function($scope){
//alert()
}]
}
}
]);
})(window.angular);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Example - example-example19-production</title>
<script data-require="jquery#*" data-semver="2.1.4" src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.1/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="app">
<expanding-grid></expanding-grid>
</body>
</html>
<-- grid template--!>
<ul id="og-grid" class="og-grid clearfix">
<li ng-repeat="item in items" grid-item scope="item"></li>
</ul>
<-- grid item template--!>
<a href="#" data-title="{{item.title}}" data-description="{{item.description}}" >
<img src="https://gmat.economist.com/sites/gmat.economist.com/files/u49/debrief.gif" alt="img01" />
</a>
Well... adding append in a $timeout seems to do the trick.
element.on("click", function(event) {
scope.preview = {name:"emanuel", title:"detailed description"};
var $html = $("<div preview-item scope='preview'></div>");
var el=$compile($html)(scope);
$timeout(function(){
element.append(el);
}, 0);
});
I have the following html:
<!doctype html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="utf-8">
<title>My AngularJS App</title>
<link rel="stylesheet" href="css/app.css"/>
</head>
<body>
<div ng-controller="myCtrl">
<cmp>
<enhanced-textarea ng-model="name"></enhanced-textarea>
<h3>{{name}}</h3>
<notice></notice>
</cmp>
</div>
<script src="lib/angular/angular.js"></script>
<script src="js/directives.js"></script>
<script src="js/controllers.js"></script>
<script src="js/app.js"></script>
</body>
</html>
I suspect there is an issue with my app.js:
'use strict';
angular.module('myApp', [
'myApp.directives',
'myApp.controllers'
]);
Here is controllers.js:
'use strict';
angular.module('myApp.controllers', [])
.controller('myCtrl', ['$scope', function($scope) {
$scope.name = 'test';
}]);
And finally directives.js:
'use strict';
angular.module('myApp.directives', [])
.directive('cmp', function () {
return {
restrict: 'E',
controller: 'cmpCtrl',
replace: true,
transclude: true,
scope: {
name: '='
},
template: '<div ng-transclude></div>'
};
})
.controller('cmpCtrl', ['$scope', '$element', '$attrs' , function ($scope, $element, $attrs) {
$scope.$parent.$watch('name', function (newVal) {
if (newVal) {
$scope.$parent.updatedSize = newVal.length;
console.log(newVal.length);
}
}, true);
}])
.directive('enhancedTextarea', function () {
return {
restrict: 'E',
replace: true,
transclude: true,
template: '<textarea ng-transclude></textarea>'
};
})
.directive('notice', function () {
return {
restrict: 'E',
require: '^cmp',
replace: true,
scope: {
updatedSize: '='
},
template: '<div>{{size}}</div>',
link: function ($scope, $element, $attrs, cmpCtrl) {
console.log(cmpCtrl);
$scope.$parent.$watch('updatedSize', function (newVal) {
if (newVal) {
$scope.size = newVal;
}
}, true);
}
};
});
My code is bloated I know, but I am in the process of pruning it down. Bear with me.
I don't understand why the size model attribute inside the notice element is not updated...
Full app is located on github here
The problem is scope inheritance, your enhancedTextarea directive' scope inherits the name property from your controller because it's undefined. But as soon as you change the textarea value, it's property is created and what you change after that changes this directive's scope property.
Take a look at this DEMO.
When you inspect the console without changing the textarea, you won't see the name property of the scope. When you type something, you see the property is created which will override the parent's scope name property.
When you change the code like this, it works:
<enhanced-textarea ng-model="name"></enhanced-textarea>
<cmp>
<h3>{{name}}</h3>
<notice></notice>
</cmp>
DEMO
In order to create loosely coupled code, I recommend you not to rely on $scope.$parent inside you directives. You should try directive bindings to bind with parent properties.
I have a widget that I'm instantiating using ng-repeat. Initial creation works fine, but after that it stops updating. Here's an excerpt from index.html:
<div>
<x-node ng-repeat="node in nodes"></x-node>
</div>
partials/node.html:
<div>{{node.name}}</div>
And the directive:
angular.module('directive', []).directive('node', function() {
return {
restrict: 'E',
scope: true,
templateUrl: 'partials/node.html',
replace: true,
compile: function(tElement, tAttrs, transclude) {
return {
post: function(scope, iElement, iAttrs) {
scope.$on('$destroy', function(event) {
console.log('destroying');
});
}
};
}
};
});
If I modify the list of nodes in the console like this:
var e = angular.element($0);
var s = e.scope();
s.nodes.splice(1,1);
s.$apply()
... then the $destroy callback runs, but the rendered elements do not change. Is there something I'm missing from my directive?
Demo: Plunker
It seems this was indeed a bug, which is fixed in the 1.2 series of AngularJS. Here's an updated demo that uses 1.2.
index.html:
<!DOCTYPE html>
<html ng-app="my-app">
<head lang="en">
<meta charset="utf-8">
<title>Custom Plunker</title>
<link rel="stylesheet" href="style.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="AppController">
<div id="ct">
<x-node ng-repeat="node in nodes"></x-node>
</div>
<button id="test">Remove element [1]</button>
</body>
</html>
app.js:
var app = angular.module('my-app', [], function () {
})
app.controller('AppController', function ($scope) {
$scope.nodes = [{
name: 'one'
}, {
name: 'two'
}, {
name: 'three'
}];
})
app.directive('node', function() {
return {
restrict: 'E',
scope: true,
templateUrl: 'node.html',
replace: true,
compile: function(tElement, tAttrs, transclude) {
return {
post: function(scope, iElement, iAttrs) {
scope.$on('$destroy', function(event) {
console.log('destroying');
});
}
};
}
};
});
$(function(){
$('#test').click(function(){
var el = $('#ct').children().first();
if(el.length){
var e = angular.element(el[0]);
var s = e.scope();
s.nodes.splice(1,1);
s.$apply()
}
})
});
node.html:
<div>{{node.name}}</div>