AngularJS: ng-click on img? Manipulating images (kind of gallery-like) with jQuery?
Asked Answered
M

4

16

Should ng-click work with img tag ?

<img ng-src="img" ng-click="openNewWindow(url)/>

myFunction is defined in controller and is $scope available … Nothing gets called; any ideas?

(I would like to open a new tab/window when image is clicked, but I don't even get into my function)

Thanks for any info

EDIT I probably rushed myself when first asking this question. I know now why it doesn't work in my case: I am manipulating images with jQuery for some kind a 'gallery' effect … (if anyone has an idea how to do that in AngularJS please bring it on). This is the html I am talking about:

<div class="commercial-container">
    <img class="commercial" ng-src="pathToImageOrImageVar" ng-click="openNewWindow(urlToOpen)" />
    <img class="commercial" ng-src="pathToImageOrImageVar" ng-click="openNewWindow(urlToOpen2)" />
    <img class="commercial" ng-src="pathToImageOrImageVar" ng-click="openNewWindow(urlToOpen3)" />
    <img class="commercial" ng-src="pathToImageOrImageVar" ng-click="openNewWindow(urlToOpen4)" />
</div>

And here the jQuery with which I create fade-in/fade-out effect (showing one image, then the next and so on indefinitely)

 function fadeInLastImg(){
    var backImg = $('.commercial-container img:first');
    backImg.hide();
    backImg.remove();
    $('.commercial-container' ).append( backImg );
    backImg.fadeIn();
};

So my real question is this:

  • How can I get the same behaviour as with my jQuery so that images will be ng-clickable?

You can of course provide a better solution (perhaps AngularJS one) for changing images like this if you know one …

Thank you

Marilou answered 13/3, 2014 at 15:27 Comment(3)
Could you please provide some more information? Post the whole HTML-Scope of the Controller as well as the controller iteslf. Else its gonna be hard to guess what could be wrong.Knepper
Could you provide a fiddle or something??Furnary
I can't make it to work in fiddle as it does in my case :/Marilou
D
27

Yes, ng-click works on images.

Without further code I can't tell you why yours isn't working, but the code you have pasted will call myFunction in the scope of the controller governing that element.

EDIT

You definitely don't need to use jQuery for this, and it's not really thinking about it in an "angular" mindset if you do.

My suggestion is to make a directive to do this. I've created a plunker with a simple example of what it could look like.

Here's a summary:

Note: Because animation is important to you, make sure you include the ng-animate src and include it as a dependency in your app module definition. Use the same version of animate as base angular.

HTML

<script src="http://code.angularjs.org/1.2.13/angular.js"></script>

<script src="http://code.angularjs.org/1.2.13/angular-animate.js"></script>

Javascript

angular.module("gallery", ['ngAnimate'])

Now Define a template for your directive:

galleryPartial.html

<div class="container">
  <img ng-src="{{image.url}}" 
       alt="{{image.name}}" 
       ng-repeat="image in images" 
       class="gallery-image fade-animation"
       ng-click="openInNewWindow($index)"
       ng-show="nowShowing==$index">
</div>

This template simply says "I want one image for every item listed in the 'images' array from the scope. The src is should be the url property of the image, and the alt text should be the name. When I click an image, run the openInNewWindow function passing the index of that image in the array. Finally, hide images unless the nowShowing variable is set to their index."

Also note the class fade-animation. This could be called anything, but this is the class we'll use to define the animation in CSS later.

Next we write the directive itself. It's pretty simple - it just has to use this template, and then define the openInNewWindow function, as well as iterate nowShowing through the array indexes:

.directive('galleryExample', function($interval, $window){
  return {
    restrict: 'A',
    templateUrl: 'galleryPartial.html',
    scope: {
      images: '='
    },
    link: function(scope, element, attributes){
      // Initialise the nowshowing variable to show the first image.
      scope.nowShowing = 0;

      // Set an interval to show the next image every couple of seconds.
      $interval(function showNext(){
        // Make sure we loop back to the start.
        if(scope.nowShowing != scope.images.length - 1){
          scope.nowShowing ++;
        }
        else{
          scope.nowShowing = 0;
        }
      }, 2000);

      // Image click behaviour
      scope.openInNewWindow = function(index){
        $window.open(scope.images[index].url);
      }
    }
  };
})

You will see I have used an isolate scope to make this directive reusable and to keep things separated nicely. You don't have to do this, but it's good practice. The html for the directive must therefore also pass the images you want to put in the gallery, like so:

index.html

  <body ng-controller="AppController">
    <div gallery-example="" images="imageList"></div>
  </body>

So the last bit of javascript we need to write is to populate that images array in the AppController scope. Normally you'd use a service to get a list of images from a server or something, but in this case we'll hard code it:

.controller('AppController', function($scope){
  $scope.imageList = [
    {
      url: 'http://placekitten.com/200/200',
      name: 'Kitten 1'
    },
    {
      url: 'http://placekitten.com/201/201',
      name: 'Kitten 2'
    },
    {
      url: 'http://placekitten.com/201/202',
      name: 'Kitten 3'
    },
    {
      url: 'http://placekitten.com/201/203',
      name: 'Kitten 4'
    }
  ]
})

Finally, styling. This will also define the animation (note the use of ng-hide classes etc). I strongly recommend you read up on this here as it is too big a subject to cover in this (already long!) answer:

.fade-animation.ng-hide-add,
.fade-animation.ng-hide-remove {
  -webkit-transition:0.5s linear all;
  -moz-transition: 0.5s linear all;
  -o-transition: 0.5s linear all;
  transition:0.5s linear all;

  display:block !important;
  opacity:1;
}

This is your end result

Dysphasia answered 13/3, 2014 at 16:24 Comment(2)
first thank you for your time - and you are right; ng-click does work like I described. But unfortunately in my case when using jQuery as well it doesn't. please see my edited question for further detailMarilou
End result won't open anything unfortunately; just says "Not Found". any ideas?Marilou
K
0

EDIT Since as you said in the comments bootstrap is not an option for you, i would suggest you write your own little directive. There is probably tons of tutorial out there like this


The Problem in your case is, that you manipulate the DOM from outside the Angular-Scope. So Angular iteslf doesnt even know about those new image-elements, and further not about the ng-click and ng-src directive. This would only be the case, if you would use Angulars own $compile-Service to put the images back into the DOM.

I would recommend you to use Angular-UI Bootstrap for an image gallery. Else, you would need to create your own Directive for this, but why reinvent the wheel?

Knepper answered 14/3, 2014 at 7:45 Comment(5)
Thank you for your time. With UI bootstrap I have to use bootstrap's CSS which I don't for my page. It usually breaks custom CSS, at least it did when I tried to use it for just parts of page. And I am not sure if carousel (gallery) is customisable enough for me: you probably can't remove everything but image right?Marilou
For me, the bootstrap-css never broke anything. But if thats not an option for you, the only thing left is to write your own directive. See the Edit in my answer.Knepper
I ended up wrapping images in <a href> element and changed jQuery to take first <a> instead of <img> with a:first … Thank you for your answer againMarilou
Not a really nice and "angular" way of doing things - but if it works for you, then alright ;)Knepper
I know but since things needed to be done and there's never enough time to dig into more details I went with it (this doesn't mean I don't agree with you, I totally do)Marilou
M
0

I ended up wrapping each image with link and changing jQuery appropriately. It was the fastest and easiest for me.

<a href="url" target="_blank">
   <img class="commercial" ng-src="pathToImageOrImageVar"/>
</a>

And changed line

var backImg = $('.commercial-container img:first');

changed to

var backImg = $('.commercial-container a:first');
Marilou answered 14/3, 2014 at 10:37 Comment(0)
F
0

I had this issue in case when I used aliases of angularJS. If I wrote something like this:

function someController($scope) {
    var vm = this;

    vm.switchSelected = function (passedEvent) {
    }
}

and then if in html code to write the following:

<div ng-controller="toolBoxController as tbc">

then in order to use switchSelected you need write something like this:

<img ng-src="{{si}}" width="230px" ng-click="tbc.switchSelected($event)"/>

so, check did you used

 var vm=this;

in your controller. Then you need to add aliasing to your html part.

Fikes answered 15/2, 2016 at 16:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.