Search code examples
phpangularjsangularjs-directivepartialmodal-window

Angular modal window function not working properly


I have an Angular function within a PHP partial page that appears to not be working properly. The function is attached to all images that are loaded on to the page from a MySQL database, and is called with ng-click="vm.openModal('custom-modal-1')".

<div id="screenings">
    <?php
    ...
    //connect to MySQL database
    ...
        while ($row = mysqli_fetch_array($result)){
            echo "<div class='img_div'>";?>

                //here is the ng-click that calls the Angular function

                <img class="modal_img img_screenings" ng-click="vm.openModal('custom-modal-1')" src='images/<?php echo $row['image']."' >";
            ...
            echo "</div>";
        }
    ?>

</div>

//here is the modal with the id that gets passed to the Angular function

<modal id="custom-modal-1">
    <div class="modal">
        <div class="modal-body">
                <img id="popup_img" src="#">
        </div>
    </div>
    <div class="modal-background"></div>
</modal>

Within the file app.js, here is the function that I'm trying to call:

app.controller('screeningsController', ['$scope', '$log', "ModalService", function($scope, $log, ModalService){

    var vm = this;

    //outputs "Hello World!" to browser console as a test
    vm.message = "Hello World!";
    $log.log(vm.message);

    vm.openModal = openModal;
    vm.closeModal = closeModal;

    function openModal(id){
        ModalService.Open(id);
    }

    function closeModal(id){
        ModalService.Close(id);
    }

}]);

When the partial page is loaded in, the test message "Hello World!" that is found within the Angular function fires, and the message appears in the browser console. However, the ng-click doesn't do anything else when any img with class modal_img is clicked on the page.

All Angular modal window materials for this code was taken from: http://jasonwatmore.com/post/2016/07/13/angularjs-custom-modal-example-tutorial

EDIT Controller as is declared at the top of the app.js file, like so:

var app = angular.module('app', ['ngRoute', 'ui.router']);

app.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {

$locationProvider.hashPrefix('');

$urlRouterProvider.otherwise("/");

 $stateProvider

 .state('home', {
    url: '/',
    templateUrl: 'pages/main.html',
    controller: 'mainController',
    controllerAs: 'vm'
 })

 .state('screenings', {
    url: '/screenings',
    templateUrl: 'pages/screenings.php',
    controller: 'screeningsController',
    controllerAs: 'vm'
 })

 //etc

Solution

  • For ng-click="vm.openModal('custom-modal-1')" to work you need to define what is vm.

    In AngularJS a template expression is evaluated in the angular scope.

    So you will need to tell the template that you intend to use screeningsController.

    It is like defining a variable/object instance in a block of code up so that the code block can use that.

    Only then the template can use the controller functions or scope functions.

    So there are two ways how you can expose controller properties/functions.

    1) By populating functions and variables on $scope 2) By populating the controller function using this like you used var vm = this;

    In your case your vm.openModal will be available to every element under id="screenings" if you declare that HTML element as below.

    <div ng-controller="screeningsController" id="screenings">

    However in order to user controller function populated on this one must use controller as syntax. So the above line becomes this:

    <div ng-controller="screeningsController as vm" id="screenings">

    In the above line you are saying that vm is screeningsController.

    It is best to use something more meaningful than just vm in case you end up using more than 1 controller say nested controllers.

    So one might just call vm as what it is - in this case screeningsController

    <div ng-controller="screeningsController as screeningsController" id="screenings"> and the ng-click becomes ng-click="screeningsController.openModal('custom-modal-1')"

    If screeningsController as screeningsController feels weird I would change that to ScreeningsController as screeningsController where by you are essentially saying screeningsController is ScreeningsController. Hence you might want to define app.controller('screeningsController' as rather app.controller('ScreeningsController'

    Its like giving a name to the Controller class/constructor so why not start with Capital case.

    You can checkout official Angular ngController documentation and the example

    Most of what I have recommended is for following best conventions. If everything else is correct your problem should just get resolved merely by
    <div ng-controller="screeningsController as vm" id="screenings">

    You may place ngController at other appropriate places but it must be some ancestor to your ng-click which needs access to that controller.