Array of elements to control view (AngularJS) - javascript

What I'm trying to do:
Is there any way to use an array of elements to populate a div with children in AngularJS?
I want to be able to have an array of custom elements, and as I update the array, it updates the view. The directives for the custom elements need to $scope.$digest() the elements each time I make an update.
Pseudo Code:
html
<div id="parent" ng-controller="parentCtrl" ng-bind-html="arrOfElems"></div>
Javascript
app.controller('levelCtrl', ['$scope', '$compile', '$element', function(scp, cmpl, elem) {
scp.arrOfElems = ['<ell></ell>', '<r-ell></r-ell>', '<sqr></sqr>'];
}]);
app.directive('ell', function() {
return {
restrict: 'E',
template: <div class="block"></div>
};
});
app.directive('rEll', function() {
return {
restrict: 'E',
template: <div class="block"></div>
};
});
app.directive('sqr', function() {
return {
restrict: 'E',
template: '<div class="block"></div>'
};
});
Ideally, the resulting html would be:
<div id="parent" ng-controller="parentCtrl" ng-bind-html="arrOfElems">
<ell>
<div class="block"></div>
</ell>
<r-ell>
<div class="block"></div>
</r-ell>
<sqr>
<div class="block"></div>
</sqr>
</div>

Create a simple loading directive that compiles them and inserts them
<div id="parent" ng-controller="parentCtrl" my-loader="arrOfElems"></div>
Untested but should work:
app.directive('myLoader',function($compile){
return function(scope, elem, attrs){
var arrOfElems=scope[attrs.myLoader];
angular.forEach( arrOfElems, function(newEl){
elem.append( $compile(newEl)(scope) );
});
}
});
DEMO

Related

How to avoid rendering directive element

Is it possible to hide my directive html element?
I mean if I have this directive:
app.js
angular.module("myApp", [])
.directive("myDirective", function() {
return {
restrict: "E",
template: "<div><p>Some text...</p></div>"
}
);
Only render the content of the template.
<div>
<p>Some text...</p>
</div>
Not the directives element:
<my-directive>
<div>
<p>Some text...</p>
</div>
</my-directive>
yes just put the replace: true in the directive. it will remove the element
angular.module("myApp", [])
.directive("myDirective", function() {
return {
restrict: "E",
template: "<div><p>Some text...</p></div>",
replace: true
}
);
Demo
angular.module("app",[])
.controller("ctrl",function($scope){
}).directive("myDirective", function() {
return {
restrict: "E",
template: "<div><p>Some text...</p></div>",
replace : true
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<my-directive>
</my-directive>
</div>
Note that replace: true is marked as deprecated (I use it myself nonetheless from time to time)
See: Explain replace=true in Angular Directives (Deprecated)

How to call link function method from html ng-click?

I have the following code in my directive:
testModule.directive('TestOne',function(){
return{
replace: true,
controller: 'TestCtrl',
link: function(scope, element, attrs){
element.on('click', function(e) {
//my own code is there
});
}
}
}
I wanted to call the above click function on ng-click with the below event in html(ng-click="mytest()"). How can I call or write exactly so that I can execute my function requirements in the above directive's element click function as per my requirements.
html:
<div test-one ng-repeat="items in testjson">
<div class="title">{{items.name}}</div>
<div class="context-menu">
<ul>
<li ng-click="mytest()">TestFunction</li>
</ul>
</div>
</div>
Thanks in advance.
First make the first letter of the directive simple
directive('TestOne',function(){
to
directive('testOne',function(){
Then create a scope function for ng-click inside the link function
.directive('testOne',function(){
return{
restrict : 'A',
replace: true,
link: function(scope, element, attrs){
scope.mytest = function() {
console.log("working")
}
}
}
})
Demo
angular.module("app",[])
.controller("ctrl",function($scope){
$scope.testjson = [{"name":"sss"},{"name":"ssss"}]
}).directive('testOne',function(){
return{
restrict : 'A',
replace: true,
link: function(scope, element, attrs){
scope.mytest = function() {
console.log("working")
}
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div test-one ng-repeat="items in testjson">
<div class="title">{{items.name}}</div>
<div class="context-menu">
<ul>
<li ng-click="mytest()">TestFunction</li>
</ul>
</div>
</div>
</div>

How to add an inner wrapper to an element in angular?

I want an angular diretive to add an inner wrapper to a DOM element. Unfortunately it's not wrapping but replacing the inner part of the element. (see plunker)
So I have this html snippet:
<body ng-app="plunker">
<div class="outer" wrapp-my-content>
<label>Name: </label>
<input type="text" ng-model="name" />
<p>Hello {{name}}</p>
</div>
</body>
The directive should change this into
<body ng-app="plunker">
<div class="outer" wrapp-my-content>
<div class="inner-wrapper">
<label>Name: </label>
<input type="text" ng-model="name" />
<p>Hello {{name}}</p>
</div>
</div>
</body>
But what I get is
<body ng-app="plunker">
<div class="outer" wrapp-my-content>
<div class="inner-wrapper">
</div>
</div>
</body>
Directive Code:
var app = angular.module('plunker', []);
app.directive('wrappMyContent', function() {
return {
restrict: 'A',
transclude: true,
replace: true,
link: function(scope, element) {
var innerWrapper = angular.element('<div class="inner-wrapper" ng-transclude></div>');
element.prepend(innerWrapper);
}
}
});
How can I fix that?
You've mixed up ng-transclude and custom transclude by link:
1. Use template of directive (demo):
var app = angular.module('plunker', []);
//Recommended angular-way
app.directive('wrappMyContent', function() {
return {
restrict: 'A',
transclude: true,
template:'<div class="inner-wrapper" ng-transclude></div>',
link: function(scope, element) {
}
}
});
2. Do transclude by custom link (demo) :
var app = angular.module('plunker', []);
//Equals transclude by your self
app.directive('wrappMyContent', function($compile) {
return {
restrict: 'A',
scope:true,
link: function(scope, element) {
var innerContent = element.html();
var innerWrapper = angular.element('<div class="inner-wrapper"></div>').append(innerContent);
//Do compile work here.
$compile(innerWrapper)(scope.$parent)
element.empty().append(innerWrapper);
}
}
});
Use a template for your '<div class="inner-wrapper" ng-transclude>' part instead of just making an element and prepending it... the ng-transclude directive won't be processed unless it's compiled which the template will be.

AngularJs, accessing parent scope from directive inside a nested ng-repeat

That's a noob question. I'm looking for the correct way to access the parent scope inside a directive in a nested ng-repeat. This is exactly what i mean:
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="section in sections">
{{section.Name}}
<div ng-repeat="item in section.Items" ng-init="parent = section">
<span class="menuItem">{{item}}</span>
</div>
</div>
</div>
And the directive:
myApp.directive('menuItem', function () {
return {
restrict: 'C',
link: function (scope, element, attrs) {
console.log(scope.$parent.section.SectionId);
}
}
});
The directive is attached to an item in the inner ng-repeat, and i need to access a property of the parent object. The problem is that i cannot access directly to the parent properties (with scope.$parent), because ng-repeat creates a new scope, and i must append the name of the object i set in the ng-repeat (in this case scope.$parent.section.):
<div ng-repeat="section in sections">
console.log(scope.$parent.section.SectionId);
JsFiddle: http://jsfiddle.net/7Lra7Loy/2/
As i want the directive to be generic, so it can be used inside other ng-repeat blocks, without being forced to use the same names in the ng-repeat, the only way i found is to use an ng-init, that would be the same in all ng-repeat blocks (ng-init="parent = section"):
<div ng-repeat="section in sections">
{{section.Name}}
<div ng-repeat="item in section.Items" ng-init="parent = section">
<span class="menuItem">{{item}}</span>
</div>
</div>
myApp.directive('menuItem', function () {
return {
restrict: 'C',
link: function (scope, element, attrs) {
console.log(scope.parent.SectionId);
}
}
});
JsFiddle: http://jsfiddle.net/7Lra7Loy/1/
Is there a better way to handle this situation? Or am i just missing something? I searched a bit, but i couldn't find anything really useful.
Template:
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="section in sections">
{{section.Name}}
<div ng-repeat="item in section.Items">
<span class="menuItem" section="{{section}}">{{item}}</span>
</div>
</div>
</div>
And directive:
myApp.directive('menuItem', function () {
return {
restrict: 'C',
scope: {
section: '#' // text-binding
//section: '&' //one-way binding
//section: '=' //two-way binding
},
link: function ($scope, element, attrs) {
console.log($scope.section);
}
}
});
JsFiddle: https://jsfiddle.net/nrkmn/26zhqbjg/

angular: calling/triigering directive method from parent scope

in my app I defined a directive which implement a simple slider with a next/prev/goto methods.
The slider then is within an html snipet managed by another controller.
The problem is that the last slide contains a form, so if the submit is ok than I would like to go to the next slide.
In old javascript I would have passed a callback to the submit method in order to apply that callback.
I made the same thing. Is this the best / angular style way to do it?
Javascript (I omitted some detail):
.directive("sfCarousel", function() {
return {
scope: true,
restrict: 'A',
controller: function($scope) {
var slides = $scope.slides = [];
var currentIndex = $scope.currentIndex = -1;
$scope.next = function() {
//mynextfunction...
}
},
link: function(scope, element, attrs) {
console.log("sf-carousel");
}
}
})
.directive("sfCarouselItem", function() {
return {
scope: true,
require: '^sfCarousel',
link: function(scope, element, attrs, sfCarouselController) {
console.log("sf-carousel-item");
sfCarouselController.addSlide(scope);
}
}
})
.controller("mycontroller", ['$scope', function($scope) {
$scope.submit = function (callback) {
//if submit is ok then
callback.apply(null, []);
}
}])
HTML:
<div sf-carousel >
<div sf-carousel-item ng-class="{'active':active}" >
<div>my first slide</div>
<div sf-label="get-started.submit" ng-click="next()" ></div>
</div>
<div sf-carousel-item ng-class="{'active':active}" >
<form>
<!--here my form-->
<button type="submit" ng-click="submit(next)">submit and go</button>
</form>
</div>
<div sf-carousel-item ng-class="{'active':active}" >
<div>my last slide</div>
<!--other things-->
</div>
</div>
You can pass the function that you what to run on the parent controller.
// directive sfCarousel
return {
transclude: true,
template: '<div class="sf-carousel" ng-transclude></div>',
// ...
};
// directive sfCarouselItem
return {
transclude: true,
scope: {
func: '&',
// ...
},
template: '<div class="sf-carousel-item" ng-transclude></div>',
}
// controller html
<div sf-carousel >
<div sf-carousel-item ng-class="{'active':active}" >
<div>my first slide</div>
<div sf-label="get-started.submit" ng-click="next()" ></div>
</div>
<div sf-carousel-item func="next()" ng-class="{'active':active}" >
<form>
<!--here my form-->
<button type="submit" ng-click="func({})">submit and go</button>
</form>
</div>
<div sf-carousel-item ng-class="{'active':active}" >
<div>my last slide</div>
<!--other things-->
</div>
</div>

Categories