0

I'm changing a Spring app from Thymeleaf to AngularJS (learning as I go) and this Ajax call that was previously working is now not even registering on in Chrome XHR. I don't have a lot of experience with these front-end frameworks so I'm not sure what changed.

index.html

            <!doctype html>
            <html ng-app="wishingWell">
            <head>
                <meta charset="UTF-8">
                <meta name="viewport"
                      content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
                <meta http-equiv="X-UA-Compatible" content="ie=edge">
                <link rel="stylesheet" href="/css/normalize.css">


                <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
                <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-route.js"></script>
                <script   src="https://code.jquery.com/jquery-3.1.1.js"   integrity="sha256-16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA="   crossorigin="anonymous"></script>
                <script src="/javascript/app.js"></script>

                <title>Wishing Well</title>
            </head>

            <body>
                    <nav class="nav">
                        <ul class="navback">
                            <li>
                                <a class="active" href="#/">The Well</a>
                            </li>
                            <li>
                                <a href="#/profile" >Profile</a>
                            </li>
                            <li>
                                <a href="#/sign-up">Sign Up</a>
                            </li>
                            <li>
                                <a href="#/login">Log In</a>
                            </li>
                            <li>
                                <a href="#/logout">Sign Out</a>
                            </li>
                        </ul>
                    </nav>

                    <div ng-view></div>

                    <script>
                        jQuery(document).ready(function($) {

                            $("#wish-form").submit(function(event) {

                                // Disble the search button
                                enableSearchButton(false);

                                // Prevent the form from submitting via the browser.
                                event.preventDefault();

                                $('#feedback').hide();
                                searchViaAjax();

                            });

                        });

                        function searchViaAjax() {

                            var search = {}
                            search["wish"] = $("#wish").val();

                            $.ajax({
                                type : "POST",
                                contentType : "application/json",
                                url : "/addwish",
                                data : JSON.stringify(search),
                                dataType : 'json',
                                timeout : 100000,
                                success : function(data) {
                                    console.log("SUCCESS: ", data);
                                    display(data);
                                },
                                error : function(e) {
                                    console.log("ERROR: ", e);
                                    display(e);
                                },
                                done : function(e) {
                                    console.log("DONE");
                                    enableSearchButton(true);
                                }
                            });

                        }

                        function enableSearchButton(flag) {
                            $("#btn-submit").prop("disabled", flag);
                        }

                        function display(data) {
                            var jsonString = JSON.stringify(data);
                            var json = JSON.parse(jsonString);
                            $('#feedback').html(json.msg);
                            $('#feedback').show();
                        }

                        $('#feedback').hover(function(){
                            $('#feedback').fadeOut(300, function(){
                                $(this).hide();
                            });
                        });

                    </script>
            </body>
            </html>

app.js

 var wishingWell = angular.module('wishingWell', [ 'ngRoute' ]);

 wishingWell.config(function($routeProvider, $httpProvider) {

$routeProvider.when('/', {
    templateUrl : 'home.html',
    controller : 'home',
    controllerAs: 'controller'
}).when('/login', {
    templateUrl : 'login.html',
    controller : 'navigation',
    controllerAs: 'controller'
}).otherwise('/');

$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';

 });



 wishingWell.controller('navigation',

 function($rootScope, $http, $location) {

    var self = this

    var authenticate = function(credentials, callback) {

        var headers = credentials ? {authorization : "Basic "
        + btoa(credentials.username + ":" + credentials.password)
        } : {};

        $http.get('user', {headers : headers}).then(function(response) {
            if (response.data.name) {
                $rootScope.authenticated = true;
            } else {
                $rootScope.authenticated = false;
            }
            callback && callback();
        }, function() {
            $rootScope.authenticated = false;
            callback && callback();
        });

    }

    authenticate();
    self.credentials = {};
    self.login = function() {
        authenticate(self.credentials, function() {
            if ($rootScope.authenticated) {
                $location.path("/");
                self.error = false;
            } else {
                $location.path("/login");
                self.error = true;
            }
        });
    };
});

My guess is that something within AngularJS is overriding jQuery, but I can't figure out what. Most of the questions about this I've seen relate to using jQuery Ajax within an AngularJS controller, but it seems like it should work outside. Also, the form data being submitted via Ajax gets put into the ng-view.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Trevor Bye
  • 595
  • 5
  • 23

1 Answers1

1

There a a few things amiss here:

  • The jQuery(document).ready(function($) is fired when the browsers emits the DOMContentLoaded. ng-view is an asynchronous fetch operation. So, most likely, when the jQuery ready function is triggered to attach your callback upon submit, the ng-view fetch operation of your template hasn't even been completed. So this would fail.
  • It's not best practice to mix jQuery AJAX in your Angular code. The reasons are many for this, but it is mostly because the DOM manipulation paradigm in AngularJS and jQuery are completely different, as can be seen by the point above.
  • What I would advise is for you to convert your AJAX calls to Angular $http requests, within a service. Services are bound to the application and can be used app wide. This will create a clean separation of concerns and avoid the jQuery - Angular race condition

The searchViaAjax can be moved to be within a controller, like so:

$scope.searchViaAjax = function() {
  $scope.search.searchResults =  SearchService.search($scope.search.searchText);
  // Where SearchService is a service you define app level, and inject into your controller
}

// HTML
<input ng-model="search.searchText">
<ul>
  <li ng-repeat="searchResult in search.searchResults">{{searchResult.text}}</li>
</ul>

And so on.

nikjohn
  • 16,079
  • 9
  • 45
  • 78
  • Thanks for your answer. It helped point me in the right direction and I now understand a lot more about how these libraries work together (and when they shouldn't). I ended up still using jQuery because there was a lot of UI manipulation going on. However, I see the point your driving at with how the DOM is treated differently. I ended up using event binding as seen in this answer http://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements?rq=1 – Trevor Bye Sep 29 '16 at 17:27
  • Glad to be of help. I would like to point out though, that while using jQuery is perfectly fine and a lot of Angular Projects do use jQuery's DOM functions (in fact Angular itself has a stripped down version of jQuery called jQLite), any DOM manipulation that is tied to model data should be tried and done through Angular as much as possible. Angular's directives are very powerful and promote modularity and reusability as well. But the learning curve is a little steep. – nikjohn Sep 29 '16 at 17:32