ng-click does not work on my directive of a slider - javascript

I use the structure provided by the yeoman with angular-generator.
The ng-click does not work in my directive, of a slider show, when I put the html directly in main.html (It only works when I put in the directive an templateurl, linked to the main.html , but this causes delay to load).
Html, that is inserted directly into main.html
<div images="images" class="slider" id="mauseOnOut">
<div class="slide" ng-repeat="image in images" ng-show="image.visible">
<a ng-href="{{image.url}}"><img ng-src="{{image.src}}" width="444" height="250"/>
<p class="texto">{{image.texto}}</p>
</a>
</div>
<ul class="minimagem" ng-show="images.length">
<li ng-repeat="image in images"><a ng-click="returner($index)"><img ng-src="{{image.src}}" width="70" height="56"/></a></li>
</ul>
<div class="arrows">
<img src="http://s5.postimg.org/qkfwdwi7n/right_arrow.png"/>
</div>
</div>
Main part of the directive (in jsFiddle have it complete)
myApp.directive('images', function ($timeout) {
return {
restrict: 'AE',
scope:{
images: '='
},
link: function (scope) {
scope.currentIndex=0;
scope.returner = function(index){
scope.currentIndex = index;
};
scope.next=function(){
scope.currentIndex<scope.images.length-1?scope.currentIndex++:scope.currentIndex=0;
};
scope.prev=function(){
scope.currentIndex>0?scope.currentIndex--:scope.currentIndex=scope.images.length-1;
};
scope.$watch('currentIndex',function(){
scope.images. forEach(function(image){
image.visible=false;
});
scope.images[scope.currentIndex].visible=true;
});
},
};
});
Put an example in jsFiddle ; when use angular 1.1, on jsFiddle, operate normally, with 1.2 or higher does not work. In my application I use the angular 1.3.10 .
How could make it work in my application? It could be to ' compile ' or in some other way , the important thing is the click staying active in the image thumbnails and arrows .
Edited: I came back with the best known directive , best to understand.

Related

Problems with Angular button

I'm creating my first Angular app and ran into a couple things that I just can't figure out. Whenever I include this:
<button ng-hide="results.length === projects.length" ng-click="limit = limit +3; gotoBottom()">Show More</button>
Inside of my template the app refuses to load but if I paste it anywhere outside of the template it works fine. I'd like to keep the button inside the template if at all possible so what on earth am I doing wrong?
Also, I'd like that button to also scroll to the #footer div and the ng-click doesn't seem to run this bit code:
$scope.gotoBottom = function() {
$location.hash('footer');
$anchorScroll();
};
I've created a Plunker of my code that can be found here:
https://plnkr.co/edit/MP4Pp4WLcn5EFb3pTEXx
By "template" if you are talking about projects template. Here is what you need to do.
Explanation:
The projects template need to have only one root element, so I added a div to wrap your project listing and show more button.
<div>
<div class="cards" ng-init="limit = 3">
<div class="card" ng-repeat="project in projects | limitTo: limit as results">
<div class="card-image">
<img src="{{project.img}}" alt="{{project.name}}" />
</div>
<div class="card-copy">
<h2>{{project.name}}</h2>
<p>{{project.desc}}</p>
<p><i class="fa fa-location-arrow"></i></p>
</div>
</div>
</div>
<button ng-hide="results.length === projects.length" ng-click="limit = limit +3; gotoBottom()">Show More</button>
<div id="footer" name="footer"></div>
</div>
For auto scroll: inject $timeout service
Explanation:
You did not had any div named footer so I added one just below the show more button and added a 100ms timeout, so that after your 3 projects load, it will scroll to the footer div. $timeout is very necessary because need to first render your projects and then scroll.
$scope.gotoBottom = function() {
$timeout(function() {
$location.hash('footer');
$anchorScroll();
}, 100);
};
Working Plunker: https://plnkr.co/edit/U3DDH57nh0Mqlpp2Txi4?p=preview
Hope this helps!
change the below code in projects.js
angular.module('portfolioApp')
.directive('projects', function() {
return {
templateUrl: 'projects.html',
controller: 'mainCtrl',
replace: true // remove directive tags
};
});
to
replace: false
it should do the trick. Plunker Link here

angular, access to scope outside of the ng-view wrapping div

I am trying to set up custom themeing on my app, so what I am doing is letting the user choose certain themes and it will change the apps theme holistically. I have a service which sends a piece of json and listens for it changing inside the controller of each view. Now this works fine within the view itself - for reference here's some snippets of the working code.
my factory controlling the theme -
angular.module('demoApp')
.factory('templatingFactory', function () {
var meaningOfLife =
{
'h1': '#ea6060',
'bg': '#ffffff'
};
return {
setTheme: function(theme) {
meaningOfLife = theme;
},
getTheme: function() {
return meaningOfLife;
}
};
});
One of my example controllers showing and changing the theme (and listening for changes)
$scope.themeStore = templatingFactory.getTheme();
console.log($scope.themeStore);
//send new themes
$scope.themeOne = function () {
var newT1 = { 'h1': '#8A6516',
'bg': '#000000'};
templatingFactory.setTheme(newT1);
};
$scope.themeTwo = function () {
var newT2 = { 'h1': '#ffffff',
'bg': '#ea6060'};
templatingFactory.setTheme(newT2);
};
$scope.themeThree = function () {
var newT3 = { 'h1': '#ea6060',
'bg': '#ffffff'};
templatingFactory.setTheme(newT3);
};
//listen for new themes
$scope.watchThemes = templatingFactory.getTheme();
$scope.$watch(templatingFactory.getTheme, function (newTheme) {
$scope.themeStore = newTheme;
});
and then on the template/view itself i do something like this -
<h3 ng-style="{ 'color' : themeStore.h1 }">Title</h3>
So my issue is that this works fine inside the view. However the ng-view tag is inside the body and outside of it are the body containers, as well as the header and footer menus that I would like to be able to hook onto with this theme object. So my quesiton is, is there any way to use that scope outside of the ng-view? I don't think it's possible but I'm not sure how else I could access and put a ng-style on the header footer and body to change some css on it with this method I am using.
So for a simple reference it looks like this -
<body ng-app="myApp">
<div class="container">
<div class="header" ng-style="{ 'background-color' : themeStore.bg }">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<i class="fa fa-bars"></i>
</button>
<div class="headerLogo"></div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
</ul>
</div>
</div>
<div ng-view class="velocity-opposites-transition-slideUpIn" data-velocity-opts="{ duration: 500 }" ng-style="{ 'background-color' : themeStore.bg }"> </div>
<div class="footer">
<p></p>
</div>
</div>
</body>
So as you can see - I'm trying to hook onto the header to change the background color, which does not work like this. What I noticed though, is if I put it on the ng-view div itself, it works alright.
I would much appreciate any input as I've been stuck on this for a while. Thank you for taking the time to read!
The DOM elements outside of your ng-view must have controllers of their own, with templatingFactory injected as a dependency.
First I would modify the html like so:
<div class="header" ng-controller="headerController" ng-style="{ 'background-color' : themeStore.bg }">
Then add headerController to your module:
angular.module('demoApp').controller('headerController', function($scope, templatingFactory){
$scope.themeStore = templatingFactory.getTheme();
$scope.$watch(templatingFactory.getTheme, function (newTheme) {
$scope.themeStore = newTheme;
});
});
A more reusable solution would be to create a directive that adds this controller functionality to whatever DOM element it is applied to, but the above is a little more straight forward.
I think the best way to have angular functions and variables outside ui-view or ng-view is to use a global service. in this case you should do your theming logic inside 'templatingFactory'. Then inject this service not in your controllers, but in your module.
angular.module('demoApp').run(['$rootScope', 'templatingFactory', function($rootScope, templatingFactory){
$rootScope.templatingService = templatingFactory;
}]);
So your service will be avaible in the $rootScope. now you can use it this way.
<body ng-app="myApp">
<div class="container">
<div class="header" ng-style="{ 'background-color' : templatingService.getTheme().bg }"> </div>
</div>
</div>
ps: I'm relative new in angular too, so I don't know nothing about good/wrong practices!
For the directive approach, a simple example might look something like this:
demoApp.directive('themeHeader', function (templatingFactory) {
return {
restrict: 'A',
link : function (scope, element, attrs) {
scope.$watch(templatingFactory.getTheme, function () {
element.css('background-color', newTheme.bg);
});
}
}
});
and the html would look like this:
<div theme-header>
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"><i class="fa fa-bars"></i></button>
<div class="headerLogo"></div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right"></ul>
</div>

AngularJS curstom directive and ngRepeat

I'm trying to make an planification app with AngularJS. The main feature is to create a Task.
I want to put the source of the task in a directive :
<section id="runningTasks" ng-controller='RunningTaskCtrl as ctrl'>
<task class="task" ng-repeat='task in ctrl.tasks'></task>
</section>
For each task, I add it in the div.
Here is my directive definition :
.directive('task', function(){
return {
restrict: 'EA',
replace:'true',
templateUrl: '/Planificator/directives/task/task.html',
link : function(scope, element, attrs){
var date = $(element).find(".datepicker");
date.datepicker();
date.datepicker("option", "dateFormat", "dd-mm-yy");
}
};
})
And the content of task.html :
<div class="task" ng-click="task.editting = true" task>
<h1>{{ task.title }}</h1>
<p>
{{ task.comment }}
</p>
<div class="edit-task" ng-show="task.editting">
<form ng-submit="ctrl.propose(task)">
... form stuff ...
</form>
</div>
</div>
My problem is when I run my page, I get an error :
Error: [$compile:multidir] http://errors.angularjs.org/1.2.26/$compile/multidir?p0=task&p1=task&p2=tem…3D%20true%22%20task%3D%22%22%20ng-repeat%3D%22task%20in%20ctrl.tasks%22%3E
at Error (native)
(the clean link : Angular error generator)
I already had this problem before and I just put the content of the template in the ngRepeat and doesn't think anymore, but this time I would like to be things in the good way.
Thank you for the answers !
Your problem is:
<div class="task" ng-click="task.editting = true" task>
Since this is part of the template created from the task directive you are trying to add the task directive over and over.
Change to:
<div class="task" ng-click="task.editting = true">

Angular directive with passed innerHTML containing template code

I am using directives to try to replace some of the often-reoccurring template code that i must write with something simpler.
lets say I have the following original markup:
<!-- section with repeating stuff in it -->
<div some-attributes etc="etc" very-long-tag="true">
<p class="lead">Some description text</p>
<div class="row section short" ng-repeat="row in things">
<div class="col-sm-6 col-md-4" ng-repeat="app in row.col">
<div class="thumbnail">
<img ng-src="im/things/{{app.image}}" alt="..." class="img-circle" width="250">
<div class="caption">
<h3>{{app.name}}</h3>
<p>{{app.desc}}</p>
</div>
</div>
</div>
</div>
</div>
and I want to simplify it by doing something like this:
<!-- section with repeating stuff in it -->
<xx title="Some description text">
<!-- this innerHTML gets passed to the directive -->
<div class="row section short" ng-repeat="row in things">
<div class="col-sm-6 col-md-4" ng-repeat="app in row.col">
<div class="thumbnail">
<img ng-src="im/things/{{app.image}}" alt="..." class="img-circle" width="250">
<div class="caption">
<h3>{{app.name}}</h3>
<p>{{app.desc}}</p>
</div>
</div>
</div>
</div>
<!-- end of innerHTML -->
</xx>
...where there are a several attributes that can be used to shorten the overall block, the directive is currently written this way:
_d.directive('xx', function() {
return {
scope: {
'color': '=',
'option': '=',
'title': '=',
'image': '=',
'image-pos': '=',
'image-size': '='
},
restrict: 'E',
transclude: false,
template: function(element, scope) {
var inside = 'x';
var content = element[0].innerHTML;
var title = scope.title;
var color = scope.color ? 'style="background-color: '+scope.color+'"' : "";
var title = scope.title ? '<h2 class="centertext marginBottom20">'+scope.title+'</h2>' : '';
return ['<div class="section row short" '+color+' ng-transclude>',
title,
content, //this may contain {{template code}}, but it always gets omitted
'</div>'
].join("\n");
},
};
});
The problem is that the existing HTML always gets omitted if it contains any {{angular template code}}.
How do I write the directive so that it still honors the template code?
Ive successfully fixed the issue with the directive, but it took several steps.
Use the correct scope properties. instead of using '=', I used '#'
That was based on the following link: What is the difference between '#' and '=' in directive scope in AngularJS?
The thing to note about scope isolation using #, =, and & affects the way you must refer to the variable in the template. for example, using = means that I would refer the variable without brackets while using # would refer to the variable with {{brackets}}.
Like I mentioned in the first point, after adjusting the scope properties, i needed to go back and refer to the variables in the correct way depending on how the scope was defined.
ng-transclude when used with {...transclude: true,...} requires that I actually put a container somewhere in the template for that transcluded content. Here's an example of that:
return ['<div class="section row short" '+color+' ng-transclude>',
title,
'<div ng-transclude>', //this is the container for the original innerHTML, transcluded
content, //this may contain {{template code}}, and gets transcluded
'</div>
'</div>'
].join("\n");
Only then did the directive work as expected. Also, props to #rob for providing me with this introductory link, https://egghead.io/lessons/angularjs-components-and-containers.

Angular JS: binding in ng-show not working

I have a directive and a controller:
app.directive('responseBox', function(){
return {
restrict: 'E',
transclude: true,
templateUrl: 'responseBox.html',
link: function(scope, element, attrs) {
element.bind("click", function () {
scope.toggle();
})
}
}});
and a controller:
app.controller('responseBoxCtrl', function($scope) {
$scope.opened = false;
$scope.toggle = function() {
$scope.opened = !$scope.opened;
console.log($scope.opened);
}});
responseBox.html:
<div class="promptBlockResponse" ng-transclude>
<div class="btn-toolbar" style="text-align: right;">
<div class="btn-group" ng-show="opened">
<a class="btn btn-link" href="#"><i class="icon-pencil icon-white"></i></a>
<a class="btn btn-link" href="#"><i class="icon-remove icon-white"></i></a>
</div>
</div>
And in the main html file:
<response_box ng-controller="responseBoxCtrl"></response_box>
I want the btn-group to show when the opened variable is true. When I click the responseBox I can see the variable toggling, but the btn-group does not show/hide. What am I missing?
So repeating what Josh and I said in the comments above, the click handler runs "outside" of Angular, so you need to call scope.$apply() to cause Angular to run a digest cycle to notice the change that was made to scope (and then it will update your view):
$scope.toggle = function() {
$scope.opened = !$scope.opened;
console.log($scope.opened);
$scope.$apply();
}});
The link function can be eliminated by using ng-click in the template:
<div class="promptBlockResponse" ng-transclude ng-click="toggle()">
With Angular 1.3 and 1.2 the following snippet from an HTML template for a custom element directive:
<div ng-click="toggle($event)"></div>
<div ng-show="data.isOpen"></div>
And a snippet from the controller for that custom directive:
$scope.toggle = function ($event, destinationState) {
....
data.isOpen = true; //this is in scope and a digest cycle is already running
//calling $scope.$apply will cause an error
demonstrates an in scope scenario where you do need to use $apply.
I came across this SO question because I was using double brackets in my
<div ng-show="{{data.isOpen}}">
Changing to
<div ng-show="data.isOpen"></div>
got my binding working when I thought at first I had a scope issue.
So in angular 1.2 and 1.3 ng-click is not "outside" of Angular, at least using the signature I used for my toggle function and is explained here:
$apply already in progress error
I discovered my double bracket ng-show issue that I initially thought was a scope issue thanks to this SO:
why doesn't ng-show remove class ng-hide

Categories