Ionic ion-slide-box Update / Slide with ng-repeat - angularjs

I try to get the ion-slide-box start at certain index.
slidebox-controller :
$ionicSlideBoxDelegate.slide(index);
slide-box-temp :
<ion-slide ng-repeat="pic in pictures"><div>...</div></ion-slide>
This doesn't work. Maybe because the slide-box hasn't been rendered yet.
Is there another way to start the slide-box at a certain index?

Template:
<ion-slide-box active-slide="myActiveSlide">
Controller:
$scope.myActiveSlide = index;

I have try using active-slide, but i had better control using this directive, to know when the ng-repeat is rendered
angular.module('starter')
.directive('repeatDone', function () {
return function (scope, element, attrs) {
if (scope.$last) { // all are rendered
scope.$eval(attrs.repeatDone);
}
}
})
HTML :
<ion-slide-box>
<ion-slide ng-repeat="day in week" repeat-done="repeatDone()" >
In your controller
$scope.repeatDone = function() {
$ionicSlideBoxDelegate.update();
$ionicSlideBoxDelegate.slide($scope.week.length - 1, 1);
};

Related

Use ngAnimate on template in directive

I have this function,
app.directive('movieDetails', MovieDetailsDirectiveFn)
.controller('MovieRowCtrl', ['$scope', '$rootScope', MovieRowCtrlFn]);
function MovieDetailsDirectiveFn() {
return {
restrict: 'E',
scope: {
movie: '='
},
templateUrl: '/tpl.html',
// template: '<div class="movie" style="background-image:url(https://image.tmdb.org/t/p/w1280{{movie.backdrop}})">{{movie.title}}</div>'
}
}
function MovieRowCtrlFn($scope, $rootScope) {
$scope.selectedMovie;
$scope.rowActive = false;
$scope.$on('movieRowActivated', ($event, dataObject) => {
if ($scope.$id != dataObject.targetScopeId) {
$scope.rowActive = false;
}
});
$scope.updateSelectedMovie = function updateVisibleMovieIndexFn(movie) {
$scope.selectedMovie = movie;
$rootScope.$broadcast('movieRowActivated', {targetScopeId: $scope.$id});
$scope.rowActive = true;
console.log ('hello')
}
}
And this html,
<div class="content" ng-repeat="movie in movieGroup" ng-init='$movieIndex = $index'>
<a href='' ng-click='updateSelectedMovie(movie)'>{{ movie.title }}</a>
</div>
<div ng-if='rowActive'>
<movie-details movie='selectedMovie'></movie-details>
</div>
When a user clicks on a button the updateSelectedMovie function triggers and the directive element movie-details is updated with new information.
Check the plunker here http://plnkr.co/edit/Ea1OtRUc1wvC4UNw1sNi?p=preview
What I want to do is animate a fadeOut/fadeIn transition when the movie-details directive element changes content. I've used ngAnimate on ui-router elements, since they get the ng-enter ng-animate classes etc. but that doesn't work with a directive.
For anyone having the same problemn. I "fixed" this by putting a ui-view inside the template that's being loaded by the directive. And fixed a state with it. So now the directive creates a template and goes to another state. The state then places the template inside the freshly created ui-view (from the directive) and now I can animate that element.

angular fall back image on background-image error

I've used this sort of directive before for a fallback image if the image does not load correctly.
app.directive('fallbackSrc', function () {
var fallbackSrc = {
link: function postLink(scope, element, attrs) {
element.bind('error', function() {
angular.element(this).css("background-image", attrs.fallbackSrc);
});
}
}
return fallbackSrc;
});
This works great when it is placed on the html like this, of course the directive would replace the src of the image instead of modifying the css:
<img fallback-src="http://google.com/favicon.ico" ng-src="{{image}}"/>
I currently have a background-image though:
<div class="issue-gallery-container" fallback-src="http://google.com/favicon.ico" style="background-image: url({{ AWS }}images/cover/{{ item.volume.number }}.{{ item.number }}.png)">
</div>
The directive right now does not pick up the error on the element since it occurs in the elements css. How would I modify the directive to listen for an error on the elements background-image?
I would setup a "dummy" img directive that changes its parent css. Or you could create a a template to simplify things even more.
Here is a working plunker http://plnkr.co/edit/334WIH2VUGReVTUYt2Tb?p=preview
Code is a bit messy but it works.
app.directive('backgroundFallbackSrc', function () {
return {
link : function(scope, element, attrs) {
element.bind('error', function() {
element.parent().css('background-image', 'url("' + attrs.backgroundFallbackSrc + '")');
});
}
}
});
html
<div class="issue-gallery-container" style="display:block; height:2000px;">
<img background-fallback-src="http://keithfimreite.com/BlogFiles/keithfimreite/SAAS.jpg"
ng-src="{{invalidImage}}" style="display:none;">
</div>

Execute script/function on each iteration of ng-repeat

I am using ng-repeat on an element like this:
<div ng-repeat="aSize in BC.aOutputSizesArr" style="width:{{aSize}}px; height:{{aSize}}px;">
{{aSize}}
<canvas/>
<script>alert({{aSize}})</script>
</div>
So basically on every repeat, i need to draw to the canvas based on the value of aSize, is it possible to execute a function on every iteration of ng-repeat? I tried putting that script tag in there, but it doesnt work.
Here's an example of what I mean with using a directive.
This directive:
angular.module('directives', []).directive('alerter', function () {
return {
model: {
size: '#'
},
link: function ($scope, element, attrs, controller) {
alert(attrs.size)
}
};
});
Used like:
<alerter size=10>alert 10</alerter>
<alerter size=15>alert 15</alerter>
Will execute.
You can use a custom directive or the directive ngInit
and pass a function from the controller.
This directive will execute once the tag is created by the ngRepeat.
<canva ng-init="function()"/> <!-- function from $scope -->
As #Jorg said, create a directive:
.directive('myCanvas', function(){
return {
scope: {
size: '=size'
},
template: '<canvas></canvas>',
link: function(scope, elem, attrs){
alert(scope.size);
}
};
});
Then inside your ng-repeat
<div ng-repeat="aSize in BC.aOutputSizesArr">
{{aSize}}
<my-canvas size="aSize"/>
</div>
This was quickly written and untested, but hopefully you get the idea. Just remember that the example above is just one way of binding, depending on your requirements for aSize (like can it be changed dynamically, etc).
<tr ng-repeat="app in appList" ng-init="getActivationFunction(app)"> <!-- function from $scope -->
<td><h4> {{ app.Name }} </h4></td>
<td> <img src="{{ app.ava_img }}"/> </td>
</tr>
in controller call the below function ...
$scope.getActivationFunction = function(modelRecieve) {
Service.getServiceDate(modelRecieve.name)
.then(function(response) {
var date = response.data.image;
$scope.app.ava_img = date;
},
// ...
};

Angular - How to use a dynamic templateUrl for a directive?

So, for whatever reason, I am trying to create a slider, where the contents of each slide are different HTML templates. So instead of an image slider, you could say it's a HTML slider.
So in my HTML I just have this code, and the controls for the slider are also inside this HTML template:
<slide-template></slide-template>
And here is my entire slide module:
(function() {
'use strict';
angular
.module('slideCtrl', [])
.directive('slideTemplate', function() {
return {
restrict: 'E',
templateUrl: 'views/slides/slide-1.html',
replace: true,
controller: 'slideController',
controllerAs: 'slides'
}
})
.controller('slideController', function() {
var vm = this;
});
})();
I'm not sure how to move forward with this, I've tried looking around but haven't found anything that I felt I could use. Inside the controller, I would like to have an array of slide template URLs and a corresponding variable to indicate the current slide:
slideUrl = [ 'views/slides/slide-1.html', 'views/slides/slide-2.html'];
slideNum = 0;
Ideally, I would then like my directive to use these variables to determine what variable it will use for templateUrl. So by default, you can see that slideNum is 0, meaning that I want to use slide1.html or slideUrl[0]. So, my templateUrl would be something like slideUrl[slideNum]. Of course, this can't be done as the directive wouldn't be able to access that data, so I'm not sure how to do this.
The end result would be that if you clicked one of the slide navigation icons, you would be updating the slideNum variable, which would instantly change the templateUrl used.
I guess I am essentially wanting a slider which doesn't rely on some images or something like that for content, but instead is a slider of actual HTML content.
Any ideas? If I haven't explained myself well enough, please let me know.
hi I would solve it like this by creating a "main.html" template and in that:
//main.html
<div ng-if="slide == 1">
<ng-include src="'slide1.html'"/>
</div>
<div ng-if="slide == 2">
<ng-include src="'slide2.html'"/>
</div>
<div ng-if="slide == 3">
<ng-include src="'slide3.html'"/>
</div>
//controller
.controller('slideController', function() {
$scope.slide = 1
//logic to switch slides
});
for animations on the slide transitions take a look at this code pen
animations
I would suggest a main directive, where you would place the different slides on one page.
For instance, the main directive:
<div ng-include src="'slider0.html'" ng-if="slider%4==0"></div>
<div ng-include src="'slider1.html'" ng-if="slider%4==1"></div>
<div ng-include src="'slider2.html'" ng-if="slider%4==2"></div>
<div ng-include src="'slider3.html'" ng-if="slider%4==3"></div>
And then in the controller of the directive you set:
$scope.slider = 0;
// Some more logic like:
$scope.slider++;
You could move this to a link function and replace your compiled slide dynamically by adding them to the slideUrl array. This method is flexible enough to allow you to manage the slides in the controller, also you could potentially pass the slide urls to the directive through an scoped attribute.
.directive('slideTemplate', function($http, $compile, $templateCache) {
return {
restrict: 'E',
replace: true,
controller: 'slideController',
controllerAs: 'slides',
link : function(scope, el, attrs) {
// Bind active slide number to controller scope
scope.slides.num = 0;
// Declare slide urls
var slideUrl = [
'views/slides/slide-1.html',
'views/slides/slide-2.html'
];
// Load a slide and replace the directives inner html
// with the next slide.
function loadSlide(template) {
// Get the template, cache it and append to element
$http.get(template, { cache: $templateCache })
.success(function(content) {
el.replaceWith($compile(content)(scope));
}
);
}
// Progress to the next slide, this is bound to the
// controllers scope and can be called from there.
scope.slides.next = function() {
var next = scope.slides.num + 1;
var slide = slideUrl[next] ? next : slide;
scope.slides.num = slide;
loadSlide(slideUrl[slide]);
}
}
}
});

Ng-controller on same element as ng-repeat - no two-way-data-binding

I can't get two-way-data-binding to work in an Angular js ng-repeat.
I have an ng-controller specified on the same element that has the ng-repeat specified -
I just learnt that by doing this, I can get a hold of each item that is being iterated over by ng-repeat. Here is the HTML:
<div ng-controller="OtherController">
<div id="hoverMe" ng-controller="ItemController" ng-mouseenter="addCaption()"
ng-mouseleave="saveCaption()" ng-repeat="image in images">
<div class="imgMarker" style="{{image.css}}">
<div ng-show="image.captionExists" class="carousel-caption">
<p class="lead" contenteditable="true">{{image.caption}}</p>
</div>
</div>
</div>
</div>
And here is the ItemController:
function ItemController($scope){
$scope.addCaption = function(){
if($scope.image.captionExists === false){
$scope.image.captionExists = true;
}
}
$scope.saveCaption = function(){
console.log($scope.image.caption);
}
}
And the OtherController:
function OtherController($scope){
$scope.images = ..
}
When I hover the mouse over the #hoverMe-div - the caption-div is added correctly. But when I input some text in the paragraph and then move the mouse away from the #hoveMe-div, the $scope.image-variables caption value is not updated in the saveCaption-method. I understand I'm missing something. But what is it?
You don't need a ng-controller specified on the same element that has the ng-repeat to be able to get each item.
You can get the item like this:
<div ng-repeat="image in images" ng-mouseenter="addCaption(image)" ng-mouseleave="saveCaption(image)" class="image">
And in your controller code:
$scope.addCaption = function (image) {
if(!image.captionExists){
image.captionExists = true;
}
};
To get contenteditable to work you need to use ng-model and a directive that updates the model correctly.
Here is a simple example based on the documentation:
app.directive('contenteditable', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, controller) {
element.on('blur', function() {
scope.$apply(function() {
controller.$setViewValue(element.html());
});
});
controller.$render = function(value) {
element.html(value);
};
}
};
});
Note that the directive probably needs more logic to be able to handle for example line breaks.
Here is a working Plunker: http://plnkr.co/edit/0L3NKS?p=preview
I assume you are editing the content in p contenteditable and are expecting that the model image.caption is update. To make it work you need to setup 2 way binding.
2 way binding is available for element that support ng-model or else data needs to be synced manually. Check the ngModelController documentation and the sample available there. It should serve your purpose.

Resources