Search code examples
javascriptangularjsexpresspugangular-directive

$scope variables reset after calling a modal directive in AngularJS


I'm making an AngularJS app that need to handle and save all the checkbox clicked by the user in a simple array of ids. If there are elements in the array and the user press the open button, a modal appear and the user can do things. Now the problem is that when i press the close button in the modal, i don't understand why but the array with all the ids is reset and i need to reselect all the checkbox to resave all the ids.

Here is my code App.js

app.controller("requestsCtrl",["$scope", "$rootScope", "crud", function($scope, $rootScope, crud){

$scope.selectedItemsId = [];
$scope.checkedAllActive = false;


//REQUESTS LOADER
crud.read(null,0, null).then(function(d){
    $scope.requests = JSON.parse(JSON.stringify(d.data));
});


//EMIT
$scope.emit = function (emitType, action) {
    console.log($scope.selectedItemsId);
    $rootScope.$broadcast(emitType, {emitType: emitType, action: action, ids: $scope.selectedItemsId});
};

$scope.checkboxHandler = function (id) {
    $rootScope.handleCheckbox($scope.selectedItemsId, id);
};
}]);

app.directive("request", function ($rootScope, $templateCache, $compile, crud) {
return {
    restrict: 'E',
    scope: { message: "=" },
    link: function ($scope, element, attr) {
        $scope.name = "request";
        $scope.ids = [];



        $scope.$on("acceptRequest", function (event, data) {

            if(data.action){
                console.log("open");
                $rootScope.InjectTemplate(element, $scope.name, $scope);
                $("#modalBackground").addClass("is-visible");
                $scope.ids = data.ids;
                $scope.setTask();
            }
            else {
                console.log("close");
                $rootScope.RemoveTemplate(element);
                $("#modalBackground").removeClass("is-visible");
                $scope.ids = [];
            }
        });


        $scope.close = function () {
            $scope.$broadcast("acceptRequest", { action: false });
        };

        $scope.setTask = function () {
            if($scope.ids.length > 0){
                crud.read($scope.ids.shift(), null, null).then(function (data, err) {
                    $scope.actualTask = new actualTask(data.data[0]);
                });
            }
            else {
                $scope.close();
            }
        };
        $scope.acceptButtonClick = function () {
            $rootScope.$broadcast("submit", {});
            if($rootScope.date){
                var objUpdate = {
                    id: $scope.actualTask._id

                };

                console.log($scope.actualTask);



            }

        };
    }
};
});

app.directive("row", function($rootScope){
return {
    restrict: 'A',
    templateUrl: "row.html",
    scope: { data: "=row", triggerController: "=change"},
    link: function($scope, element, attrs){
    }
};
});
app.run(function ($rootScope, $templateCache, $compile, crud) {
//GLOBAL VARIABLE
$rootScope.date = false;

//------------------

//HANDLE CHECKBOX
$rootScope.handleCheckbox = function (selectedIds, id) {
    var i = selectedIds.indexOf(id);
    if(i !== -1)
        selectedIds.splice(i, 1);
    else
        selectedIds.push(id);

    console.log(selectedIds);
};
//---------------


//DOWNLOAD ACTUAL TASK
$rootScope.ActualTaskOrExit = function (ids) {

    if(ids.length > 0){

        crud.read(ids.shift(), null, null).then(function (data, err) {
            console.log(data.data[0]);
            return new actualTask(data.data[0]);
        });
    }
    else {
        return false;
    }
};

//---------------

//INJECT AND REMOVE TEMPLATE
$rootScope.InjectTemplate = function (element, template, $scope) {
    var template = $templateCache.get(template);
    element.html(template);
    $compile(element.contents())($scope);
};

$rootScope.RemoveTemplate = function (element) {
    element.html("");
};
//----------------------------

//DATE FUNCTIONS
$rootScope.fromUTCtoITimestamp = function (data) {
    var date = data.split('T')[0];
    var hours = data.split('T')[1].substring(0,5);

    var year = date.split('-')[0];
    var month = date.split('-')[1];
    var day = date.split('-')[2];
    var hour = hours.split(':')[0];
    var minutes = hours.split(':')[1];

    return Date.UTC(year, month, day, hour, minutes);
};
$rootScope.fromTimestampToUTC = function (data) {
    return new Date(data).toISOString();
};
//--------------------


$rootScope.getModalTemplate = function (modalType) {
    return $templateCache.get(modalType);
};

$rootScope.getDate = function (data) {
    var t = data.split('T');
    var day = t[0].split('-');
    var dateOne = day[2] + '/' + day[1] + '/' + day[0];
    var hours = t[1].split(':');
    var dateTwo = hours[0] + ":" + hours[1];
    return dateOne + " " + dateTwo;
};
});

app.service("crud", ["$http","$location", function($http, $location){
var service = this;

service.create = function(obj){
    return $http({
        method: 'PUT',
        url: "/app/create",
        data: { obj: obj }
    });
};
service.read = function (id, status, date) {
    if(id == null && status == null && date == null) return null;
    return $http({
        method: 'GET',
        url: "/app/read",
        params: {id: id, status: status, date: date }
    });
};
service.delete = function(id){
    return $http({
        method: 'DELETE',
        url: "/app/delete",
        params: { id: id }
    });
};
service.update = function(obj, path){
    return $http({
        method: 'PUT',
        url: path == 0 ? "/app/update" : "/app/updateProfile" ,
        data: { obj: obj }
    });
};
}]);

Index.jade

script(type="text/ng-template" id="requests.html")
  h1="Richieste"
  div
    button(ng-click="emit('acceptRequest', true)" ).buttonModify="Accetta"
    button(ng-click="emit('removeRequest', true)" ).buttonTerminate="Rimuovi"
  table
    tr
      th
        a(ng-click="selectAll()")#selectAll.mdi.mdi-arrow-down-drop-circle.mdi-24px.mdi-light
      th="ORDINE"
      th="DISPOSITIVO"
      th="APPUNTAMENTO"
      th="CLIENTE"
    tr( ng-repeat="request in requests" id="{{ request._id }}" row="request" change="checkboxHandler")
  div#noData
    {{ requests.length == 0 ? "Nessuna Richiesta da mostrare" : ""}}

div#modalBackground
  request

script(type="text/ng-template" id="row.html")
  td
    input(type="checkbox" ng-model="check" value="{{ data._id }}" ng-change="triggerController(data._id)"  )
  td="{{ data.ordercode }}"
  td="{{ data.device }}"
  td="{{ data.appointment }}"
  td="{{ data.name + ' ' + data.surname }}"

Solution

  • Use the ng-if directive to add and remove the modal template. The ng-if directive creates a child scope so that any watchers and directive bindings created by the $compile service can be removed by destroying the child scope. Otherwise opening and closing of the modal leaks memory with unremoved watchers.

    $rootScope exists, but it can be used for evil

    Scopes in AngularJS form a hierarchy, prototypically inheriting from a root scope at the top of the tree. Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.

    Occasionally there are pieces of data that you want to make global to the whole app. For these, you can inject $rootScope and set values on it like any other scope. Since the scopes inherit from the root scope, these values will be available to the expressions attached to directives like ng-show just like values on your local $scope.

    Of course, global state sucks and you should use $rootScope sparingly, like you would (hopefully) use with global variables in any language. In particular, don't use it for code, only data. If you're tempted to put a function on $rootScope, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.

    Conversely, don't create a service whose only purpose in life is to store and return bits of data.

    — AngularJS FAQ