Nabil Sham Nabil Sham - 1 month ago 12
AngularJS Question

ionic/angular ng-click calls wrong function

The following code works fine if you log in and logout, but if you try to login after that the ng-click="login()" calls the logout() function. The DOM is update correctly.

.controller('AppCtrl', function($scope) {
function updateMenu(){
$scope.customMenuItems = [];
if(loggedin){
$scope.customMenuItems.push({'text':'Login','click':'login()'});
}else{
$scope.customMenuItems.push({'text':'Logout','click':'logout()'});
}
}
updateMenu();

$scope.login(){
loggedin= true;
updateMenu();
}

$scope.logout(){
loggedin= false;
updateMenu();
}


and menu.html

<ion-list>
<ion-item menu-close ng-click="{{item.click}}" ng-repeat="item in customMenuItems track by $index">
{{item.text}}
</ion-item>
</ion-list>

PSL PSL
Answer

I do not think it is a good idea to pass the handler as string on the bound data. Also if you see the console you will see parser error because ng-click needs an expression and presence of interpolation will make it an invalid expression. For the answer sake you could use $eval function of the scope (it is not same as javascript eval) that can evaluate valid angular expression against the scope, i.e something like:

 ng-click="$eval(item.click)"

<ion-item menu-close ng-click="$eval(item.click)" ng-repeat="item in customMenuItems track by $index">
     {{item.text}}
 </ion-item>

Also there are some logic issues in the code as well.

Demo

angular.module('app', []).controller('AppCtrl', function($scope) {
  var loggedin = false;

  function updateMenu() {
    $scope.customMenuItems = [];
    if (!loggedin) {
      $scope.customMenuItems.push({
        'text': 'Login',
        'click': 'login()'
      });
    } else {
      $scope.customMenuItems.push({
        'text': 'Logout',
        'click': 'logout()'
      });
    }
  }

  updateMenu();

  $scope.login = function() {
    loggedin = true;
    console.log("login");
    updateMenu();
  }

  $scope.logout = function() {
    loggedin = false;
    console.log("logout");
    updateMenu();
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<div ng-app="app" ng-controller="AppCtrl">

  <div menu-close ng-click="$eval(item.click)" ng-repeat="item in customMenuItems track by $index">
    {{item.text}}
  </div>
</div>

But ideally i would prefer doing it more explicitly than doing some black magic :), i.e as a simple approach render specific button with click handler based on the logic instead of handling the method calls via magic string in the data being bound or passing function references around.

Comments