1

I am experiencing trouble with ng-show. To specify my problem; I have a system where I want to create a user. When you do this, I want the system to generate a box with a return message - specific for .success and .error. I have created to boxes for both cases, however none of these show up when they're supposed to be set to true.

Here is my code.

Html.

<div ng-controller="SignupController as ctrl" >
                    <div class="alert alert-success" ng-show="ctrl.booleanSuccess"> 
                        <a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
                        <div>{{ctrl.feedbackSuccessMessage}}</div>
                    </div>
                    <div class="alert alert-warning" ng-show="ctrl.feedbackErrorMessage">
                        <a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
                        <div>{{ctrl.feedbackErrorMessage}}</div>
                    </div>
                </div>

Javascript.

angular.module('myApp.signup', [])


    .controller('SignupController', ["$http", function ($http) {


            var self = this;
    self.booleanSuccess = false;
            self.feedbackSuccessMessage = null;
            self.feedbackErrorMessage = null;

            //Dette sker, når signup-knappen klikkes (ng-click)
            self.signupButton = function () {
                var username = self.username;
                var password = self.password;

                $http.post('http://localhost:8080/MomondoProjectServer/api/flightinfo/createUser/' + username + '/' + password)
                        .success(function (response, status, headers, config) {
                            self.username = "";
                            self.password = "";
                            console.log(response);
                            self.booleanSuccess = true;
                            self.feedbackSuccessMessage = response.info + response.username;
                        }).error(function (response, status, headers, config) {
                            self.feedbackErrorMessage = "Failed to create user: '" + self.username + "'. Please try again.";
                            console.log(self.feedbackErrorMessage);
                });
            };

        }]);
Daniel
  • 469
  • 5
  • 15

4 Answers4

0

You should store the data inside $scope variable rather than this instance. Following code will work.

Script

angular.module('myApp.signup', [])
    .controller('SignupController', ["$scope", "$http",
        function ($scope, $http) {
            $scope.booleanSuccess = false;
            $scope.feedbackSuccessMessage = null;
            $scope.feedbackErrorMessage = null;
            //Dette sker, når signup-knappen klikkes (ng-click)
            $scope.signupButton = function () {
                var username = $scope.username;
                var password = $scope.password;
                $http.post('http://localhost:8080/MomondoProjectServer/api/flightinfo/createUser/' + username + '/' + password)
                    .success(function (response, status, headers, config) {
                        $scope.username = "";
                        $scope.password = "";
                        console.log(response);
                        $scope.booleanSuccess = true;
                        $scope.feedbackSuccessMessage = response.info + response.username;
                    }).error(function (response, status, headers, config) {
                        $scope.feedbackErrorMessage = "Failed to create user: '" + $scope.username + "'. Please try again.";
                        console.log($scope.feedbackErrorMessage);
                    });
            };
        }
    ]);

HTML

<div ng-controller="SignupController as ctrl" >
        <div class="alert alert-success" ng-show="booleanSuccess"> 
            <a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
            <div>{{feedbackSuccessMessage}}</div>
        </div>
        <div class="alert alert-warning" ng-show="feedbackErrorMessage">
            <a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
            <div>{{feedbackErrorMessage}}</div>
        </div>
</div>
Vivek
  • 11,938
  • 19
  • 92
  • 127
  • That is not the problem. Using `this` works fine, it's one of the main reasons to use controllerAs. – R. Salisbury Dec 04 '15 at 12:12
  • That is what I thought, and since our school asked us to use "this" and "self" instead, I prefer to do this :-) Thanks for the suggestion though. – Daniel Dec 04 '15 at 12:15
  • You have a **console.log(response)** in success handler. What is its o/p – Vivek Dec 04 '15 at 12:17
  • Was just to test what the reponse included - you can ignore it. – Daniel Dec 04 '15 at 12:19
  • adding everything to the $scope adds difficulty to read / understand the code. Maybe not when you write it, but when say after 6 months you have to add functionality, your entire template will be filled with magic variables, good luck finding a variable of a $scope.$parent.$parent, because it wil just work… Give your controllers an easy name, and you know where what var was assigned. – Pjetr Dec 04 '15 at 12:43
0

See this plunker, I've modified your code to use a directive instead of controllerAs, because it's better :)
I've also mocked a backend-call by resolving a promise after 1.5 seconds.

Could it be that you simply forgot to add the form to the scope (not $scope) of the controller? Because that was the only thing I had to do to make it work.

'use strict';

(function(angular) {

  angular.module('myApp', []);

  angular.module('myApp')
    .controller('SignupController', ['$q', '$timeout', function($q, $timeout) {
      var mv = this;

      mv.booleanSuccess = false;
      mv.feedbackSuccessMessage = null;
      mv.booleanError = false;
      mv.feedbackErrorMessage = null;
      mv.username = '';
      mv.password = '';

      mv.signUpHandler = function() {
        return $q(function(resolve, reject) {
          if(mv.username === '' || mv.password === '') {
            mv.booleanError = true;
            mv.feedbackErrorMessage = 'password and username are required';
            mv.booleanSuccess = false;
            mv.feedbackSuccessMessage = null;

            reject(mv.feedbackErrorMessage);
          } else {
            mv.booleanError = false;
            mv.feedbackErrorMessage = null;

            $timeout(function() {
              mv.booleanSuccess = true;
              mv.feedbackSuccessMessage = 'You are now logged in!';

              resolve(mv.feedbackSuccessMessage);
            }, 1500);  
          }
        });
      };
    }]);
  angular.module('myApp')
    .directive('signup', [function() {
      return {
        restrict: 'E',
        controller: 'SignupController',
        controllerAs: 'signupCtrl',
        templateUrl: './signup.template.html'
      };
    }]);

})(window.angular);
Pjetr
  • 1,372
  • 10
  • 20
  • Thanks for your answer. What your example does, is kinda almost exactly what I want it to do. Can you cut deeper in what you mean by "Could it be that you simply forgot to add the form to the scope (not $scope) of the controller? Because that was the only thing I had to do to make it work."? As I am not exactly sure what I got to do here and what it is I am missing :-P – Daniel Dec 04 '15 at 12:48
  • `
    ` holds no form in the snippet you've provided. Hence the controller can't ever go into the clickHandler. Because this would be out of his reach (scope). So if your code was an exact copy-paste, it would be as simple as adding your form in the div where you've declared the controller. But work with directives, as they are a lot easier to maintain.
    – Pjetr Dec 04 '15 at 13:18
  • hmmm. I'm not complettely sure I get what I am doing wrong, and what I am missing. Maybe you miss some information. Look at this link: https://gyazo.com/e0949e5cff9775578a7d1b92a5be25a4 This is the button and function that should activate the info-boxes. :) I am kinda uncertain what you mean by "holds no form" and "adding your form" - what is this exact form? And thanks for the help. Appreciated. – Daniel Dec 04 '15 at 13:39
  • http://plnkr.co/edit/Gto72ZKENhLuSkCxcSqd?p=catalogue This is exact code from my project. It is not providing backend ofc. If you cba looking at unnecessary code having no influence on the problem. – Daniel Dec 04 '15 at 14:00
  • My issue appears to be somewhere in the
    where I create the alerts and specify what should be inside them. If I remove ng-show so they always appear, it is clear that they are never provided with any info either. It looks like this. Any idea what is wrong? http://jsfiddle.net/4ktkahxx/
    – Daniel Dec 04 '15 at 14:15
  • Hi Daniel, no worries, In the screenshot it looks like it should work. If you add a console.log in the controller, does that log? I'll try and check later tonight if I can get some results :) – Pjetr Dec 04 '15 at 16:27
  • Hi, thanks for your response! Yeah, the console.log(feedbackErrorMessage) log it correctly with appropiate message. However it does not change the "
    {{signUpCtrl.feedbackSuccessMessage}}
    " at all :-( So the signup.js seem to work properly, however this DIV does not receive what is it supposed to do.
    – Daniel Dec 04 '15 at 16:42
  • I've been going over your code, The main reason why it can't work is because of typo's and I can only imagine a mixing of tutorials? Since your clearly still at the beginning of the project I would suggest to start fresh. Perhaps now would be a great time to start using browserify, or even typescript. But first start with following this tutorial: http://campus.codeschool.com/courses/shaping-up-with-angular-js/, it's a free course and it creates a lot of clarity. – Pjetr Dec 04 '15 at 19:15
  • You look for variables that are bound to the scope, so to fix the current code, just make sure all variables are prefixed with the correct controller. But mostly, my previous comment, take your time to get some of the classes from codeschool in. – Pjetr Dec 05 '15 at 11:07
  • Hm, actually i am not really at the start of the project, using ngroute with multiple views :p i will run that tutorial through, thanks! I'll look up browserify and typescript too. – Daniel Dec 05 '15 at 16:46
  • I have been looking these variables through and through, and i cant seem to place the mistake. Have you an idea where the actual problem is, not giving the div-message-box the needed access to the info? And again, thanks for your help and time. – Daniel Dec 05 '15 at 16:49
  • I have been over your code somewhat more in depth, and I found your bug. You put the bind the same controller to 2 nodes. You can solve your issue by nesting the 2 elements (modal and errors) in a single container to whom you bind the controller, or by making the controller read and write data to a service, or even better, a modalController and a errorController with a shared service which holds the data. Hope I'm not making a mistake by not reading toroughly enough this time again :D – Pjetr Dec 06 '15 at 21:21
  • ahhh. I think that makes sense. I'll look into this. Thanks alot for your effort and time :) – Daniel Dec 07 '15 at 09:29
  • No problem, mind marking this as the correct answer? :) – Pjetr Dec 07 '15 at 13:21
  • Sure thing, sorry ;-) Thanks again. – Daniel Dec 08 '15 at 10:44
0

There might be 2 things that you want:

1) 2 way binding - so that to show the alert messages whenever 'booleanSuccess' or 'feedbackErrorMessage' changes.

2) Bind the variable only once, so that when you receive any value in 'booleanSuccess' or 'feedbackErrorMessage' variable, you show it and that alert message remains on the page forever unless you do any DOM manipulation.

If you want the first thing then see the answer given by @VVK. Reason - only variables with '$scope' gets the two way binding capability. See - https://docs.angularjs.org/guide/scope. And do not confuse $scope with general meaning of scope (in javascript or angularJS). $scope is a service and needs to be injected inside controller.

If you want 2nd thing, then there are 2 approaches(could be more):

i) again register your variables with $scope but write your HTML like this:

              <div class="alert alert-success" ng-show="ctrl.booleanSuccess"> 
                    <a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
                    <div>{{::feedbackSuccessMessage}}</div>
                </div>
                <div class="alert alert-warning" ng-show="ctrl.feedbackErrorMessage">
                    <a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
                    <div>{{::feedbackErrorMessage}}</div>
                </div>

ii) Make sure that your HTML partial gets into DOM after your server call/s is/are complete. As you have mentioned using ngRoute, so the easiest way to do this - when your declare your routeprovider to show this partial on a specific location, then alongwith properties like template, controller, etc., write another property 'resolve'. Please go through - https://docs.angularjs.org/api/ngRoute/provider/$routeProvider. Make a new property of type function for the resolve object. You can use $q to make a deferred promise, return this promise from the resolve's function, and resolve this promise when server's data is received. Then send this server data as an arguement into deferred.resolve() method.

Ex.-

$routeProvider.when(someurl,{
   templateUrl : your partial's url,
   controller : SignupController,
   resolve : {
     mydata : function($q){
       var deferred = $q.defer();
            $http.post('http://localhost:8080/MomondoProjectServer/api/flightinfo/createUser/' + username + '/' + password)
                    .success(function (response, status, headers, config) {
                        angular.extend(resolve,{successData:true})
                        deferred.resolve(response); //important
                    }).error(function (response, status, headers, config) {
                        angular.extend(resolve,{successData:false})
                        deferred.resolve(response); // important
            });
     }
   }
});

now inject resolve's 'mydata' into your controller. Check in controller if it's successData is true or false and accordingly set your variables - booleanSuccess or feedbackErrorMessage.

The main point here is that your HTML partial will loaded be into DOM only after your promise inside 'resolve' gets resolved.

The ii) approach can be done by many other ways like using ng-if or ng-switch or ng-include, but resolve property is my favorite.

Also, I would suggest to simply register your variables with $scope and have fun with 2 way binding.

Caution - Don't think that controller's variables (or 'this' properties) contain references in HTML, they don't. Only way of 2 way binding in AngularJS in with $scope.

Hope this helps, actually didn't want to give this long answer.

Vineet 'DEVIN' Dev
  • 1,183
  • 1
  • 10
  • 35
-1

There is most likely a problem with your data source. The following works:

<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
<div ng-app="myApp">
    <h2>Something</h2>
    <div ng-controller="SignupController as ctrl">
        <div class="alert alert-success" ng-show="ctrl.booleanSuccess">
            <a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
            <div>{{ctrl.feedbackSuccessMessage}}</div>
        </div>
        <div class="alert alert-warning" ng-show="ctrl.feedbackErrorMessage">
            <a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
            <div>{{ctrl.feedbackErrorMessage}}</div>
        </div>
        <button ng-click="ctrl.signupButton()">Sign up</button>
    </div>
</div>
<script>
    angular.module('myApp', [])
      .controller('SignupController', ["$q", function ($q) {
          var self = this;
          self.booleanSuccess = false;
          self.feedbackSuccessMessage = 'Blah blah';
          self.feedbackErrorMessage = null;

          //Dette sker, når signup-knappen klikkes (ng-click)
          self.signupButton = function () {
              var username = self.username;
              var password = self.password;

              $q.when({
                  info: 'Logged in',
                  username: 'User'
              })
                .then(function (response) {
                    self.username = "";
                    self.password = "";
                    console.log(response);
                    self.booleanSuccess = true;
                    self.feedbackSuccessMessage = response.info + response.username;
                });
          };

      }]);
</script>
R. Salisbury
  • 1,954
  • 16
  • 17
  • Thanks. I am trying to look it through but I cant seem to find an apparent difference that solve my problem :-( – Daniel Dec 04 '15 at 12:27
  • Can you post what the response from your server is? – R. Salisbury Dec 04 '15 at 12:27
  • Yes. This is the response when I create a new user; "Object {info: "You successfully registered", username: "ladææææ"}". If that is what you meant? – Daniel Dec 04 '15 at 12:29
  • So when that user is created, I want the "ng-show="ctrl.booleanSuccess" " to be shown, rather than hidden, and include the message I made in the .success call in this div: "
    {{ctrl.feedbackErrorMessage}}
    " Does it make sense?
    – Daniel Dec 04 '15 at 12:31
  • Well, there is something else wrong somewhere that we can't see, because the above code works perfectly and is only slightly modified from your example. – R. Salisbury Dec 04 '15 at 12:53
  • My issue appears to be somewhere in the
    where I create the alerts and specify what should be inside them. If I remove ng-show so they always appear, it is clear that they are never provided with any info either. It looks like this. Any idea what is wrong? http://jsfiddle.net/4ktkahxx/
    – Daniel Dec 04 '15 at 14:15