1

I have a login form, with a submit button. When the button is clicked, a RESTful web service is called. If login is successful it redirects users to another page. If it's not, then a span with an error message should be displayed.

I tried to use ng-style to manipulate the css of a span that displays the error.

Here is my span element:

<span id="login-error-msg" class="login-error" ng-style="errorMsg">*Wrong Username/Password</span>

And here in the controller I have a following line:

$scope.errorMsg = { "display" : "none"};

And if I get response from the server that the login wasn't successful. I do this:

$scope.errorMsg = { "display": "block" };

However, nothing changes, the span element remains hidden. However, when I click on the submit button again. The style changes and thespan is visible.

How should I fix this? It seems to me like the span is rendered before the value of $scope.errorMsg is changed.

UPDATE: I tred using ng-show as suggested. Here is my span:

<span id="login-error-msg" class="login-error" ng-show="displayError">*Wrong Username/Password</span>

And, here in the controller I set: $scope.displayError = false;

An, finally when I get a response from the server. I do this:

$scope.displayError = true;

However, I still get the same problem. I only see the change if I enter the wrong data twice. One solution might be to reload the page, but that seems unneccesary.

UPDATE 2: Here is my whole code for the controller:

myApp.controller('loginController', function($scope, $rootScope, $http, $location, $timeout, SERVER_PATH) {

        $scope.displayError = false;

    $scope.login = function(){

                var username = $scope.username;
                var password = $scope.password;

                var url =  SERVER_PATH + "login/doLogin";

                var jsonObj = JSON.stringify({phoneNumber:username, password:password});

                $.blockUI({ message: '<h1><img src="images/squares.gif" /> Logging in...</h1>' });

                $http.post(url, jsonObj)
                .then(function successCallback(response) {

                        console.log(JSON.stringify(response.data));

                        var jsonResponse = JSON.parse(JSON.stringify(response.data)); 
                        console.log("JSON response status: " + jsonResponse.status);

                        if (jsonResponse.status == 0) {
                        // Login success
                        setTimeout($.unblockUI, 2000);
                        $rootScope.token = jsonResponse.token;
                        console.log("Login success. Token: " + jsonResponse.token);
                        $timeout(function() { $scope.$apply(function() { $location.path("/sign"); }); }, 2000);
                }    

                else {        
                        setTimeout(function() {
                                $.unblockUI();
                                $scope.displayError = true;
                               // $scope.errorMsg = { "display": "block" };
                        }, 2000);

                }

        }, function errorCallback(response) {
                        // called asynchronously if an error occurs
                        // or server returns response with an error status.
                        console.log("An error has occured while sending the data to the server...");
                        setTimeout($.unblockUI, 2000);
                });


};

})

UPDATE 3: I solved the issue by changing the setTimeout to $timeout as Damoon Rashidi suggested.

Now my else body looks like this:

$timeout(function(){
                        $.unblockUI();
                        $scope.displayError = true; 
                   }, 2000);
4
  • 2
    You should use ngIf to render element, You can also use ngShow/ngHide directive Commented May 22, 2017 at 10:48
  • Please provide a minimal reproducible example that reproduces the problem. As noted there are easier ways to do this but yours should also work Commented May 22, 2017 at 10:52
  • check my answer Commented May 22, 2017 at 11:07
  • Show the code used to update scope. Commented May 22, 2017 at 11:11

1 Answer 1

2

It sounds like your digest-cycle isn't running after the first click. It depends on how your async call is handled (angular's own $http methods trigger the digest cycle after they are done).

Without the context of the rest of the code it will probably work if you add a $scope.$apply() after your async actions are done.

EDIT: Yeah the setTimeout is the thing that's messing it up. Angular doesn't understand to check for changes in your scope in the timeout callback. You can either use $timeout(callback, ms) or use call $scope.$apply manually. If you use $timeout make sure inject it into your controller.

Sign up to request clarification or add additional context in comments.

1 Comment

No idea why this was downvoted, you could very well be correct. hide/show will have the same problem if there is a problem with the digest sync.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.