element.val()返回先前的值

时间:2017-03-30 00:17:48

标签: javascript angularjs angularjs-directive google-places-api

这是我的问题

我正在尝试创建一个调用指令函数的按钮,然后激活google地点' place_changed'分配给指令的事件。如果getPlace()函数没有返回结果,例如var result = scope.gPlace.getPlace();然后我想通过执行以下操作强制进行地点预测。

if( result === undefined ) {
   result = { name: element.val() }
} 

然而问题是,当首次加载页面时,此代码将起作用,但后续尝试会将var result分配给之前输入的文本。例如输入"阿德莱德"并点击按钮等于成功的过程但是现在输入墨尔本并点击按钮仍然等于"阿德莱德"



'use strict';
angular.module( "ngAutocomplete", [])
  .directive('ngAutocomplete', function() {
    return {
      require: 'ngModel',
      scope: {
        ngModel: '=',
        options: '=?',
        details: '=?',
        setFn: '&'
      },

      link: function(scope, element, attrs, controller) {

        //options for autocomplete
        var opts
        var watchEnter = false
        //convert options provided to opts
        var initOpts = function() {

          opts = {}
          if (scope.options) {

            if (scope.options.watchEnter !== true) {
              watchEnter = false
            } else {
              watchEnter = true
            }

            if (scope.options.types) {
              opts.types = []
              opts.types.push(scope.options.types)
              scope.gPlace.setTypes(opts.types)
            } else {
              scope.gPlace.setTypes([])
            }

            if (scope.options.bounds) {
              opts.bounds = scope.options.bounds
              scope.gPlace.setBounds(opts.bounds)
            } else {
              scope.gPlace.setBounds(null)
            }

            if (scope.options.country) {
              opts.componentRestrictions = {
                country: scope.options.country
              }
              scope.gPlace.setComponentRestrictions(opts.componentRestrictions)
            } else {
              scope.gPlace.setComponentRestrictions(null)
            }
          }
        }

        if (scope.gPlace == undefined) {
          scope.gPlace = new google.maps.places.Autocomplete(element[0], {});
        }

        google.maps.event.addListener(scope.gPlace, 'place_changed', function() {

          var result = scope.gPlace.getPlace();

          //hack to make sure we have an object to pass to ensure we can get results from the called function activateGetPlace
          if( result === undefined ) {
            result = { name: element.val() }
          }

          console.log("the result", result);

          if (result !== undefined) {

            if (result.address_components !== undefined) {

              scope.$apply(function() {
                scope.details = result;
                controller.$setViewValue(element.val());
              });
            }
            else {
              if (watchEnter) {
                getPlace(result)
              }
            }
          }
        })

        //function to get retrieve the autocompletes first result using the AutocompleteService
        var getPlace = function(result) {
          var autocompleteService = new google.maps.places.AutocompleteService();
          if (result.name.length > 0){
            autocompleteService.getPlacePredictions(
              {
                input: result.name,
                offset: result.name.length,
                types: opts.types,
            		componentRestrictions: opts.componentRestrictions
              },
              function listentoresult(list, status) {
                if(list == null || list.length == 0) {

                  scope.$apply(function() {
                    scope.details = null;
                  });

                } else {
                  var placesService = new google.maps.places.PlacesService(element[0]);
                  placesService.getDetails(
                    {'reference': list[0].reference},
                    function detailsresult(detailsResult, placesServiceStatus) {

                      if (placesServiceStatus == google.maps.GeocoderStatus.OK) {
                        scope.$apply(function() {

                          controller.$setViewValue(detailsResult.formatted_address);
                          element.val(detailsResult.formatted_address);

                          scope.details = detailsResult;

                          //on focusout the value reverts, need to set it again.
                          var watchFocusOut = element.on('focusout', function(event) {
                            element.val(detailsResult.formatted_address);
                            element.unbind('focusout')
                          })

                        });
                      }
                    }
                  );
                }
              });
          }
        }

        controller.$render = function () {
          var location = controller.$viewValue;
          element.val(location);
        };

        //watch options provided to directive
        scope.watchOptions = function () {
          return scope.options
        };

        scope.$watch(scope.watchOptions, function () {
          initOpts()
        }, true);

        scope.activateGetPlace = function() {
          google.maps.event.trigger(scope.gPlace, 'place_changed');
        }

        scope.setFn({theDirFn: scope.activateGetPlace});

      }
    };
  });
  
  var mechanicsearch = angular.module('mechanicsearch', ['ngRoute','ngResource','ngAutocomplete']),
    radiusOptions = [];

mechanicsearch.run(function($rootScope) {
  $rootScope.$on('handleActiveJobsPanel', function(event, args) {
      $rootScope.$broadcast('activateJobsPanel', args);
  });
  $rootScope.$on('handleActiveFinalise', function(event, args) {
      $rootScope.$broadcast('activateFinalisePanel', args);
  });
  $rootScope.$on('handleActiveSearch', function(event, args) {
      $rootScope.$broadcast('activateSearchPanel', args);
  });
});

mechanicsearch.filter('htmlToPlaintext', function() {
  return function(text) {
    return  text ? String(text).replace(/<[^>]+>/gm, '') : '';
  };
});

// mechFactory service
mechanicsearch.factory('mechFactory', function($resource,$window) {
    var mechanics = [];
    var jobs = [];

    var addMechanic = function(mechanic){
      mechanics.push(mechanic);
    };

    var getAllMechanics = function(){
      return mechanics;
    };

    var removeAllMechanics = function() {
      mechanics = [];
    }

    var addJob = function(job) {
      jobs.push(job);
    }

    var getAllJobs = function() {
      return jobs;
    }

    var removeAllJobs = function() {
      jobs = [];
    }

    return {
      getMechanics: function(location,radius) {
        return $resource('/ajax/api.cfm?api=mechanic&function=getMechanicByLocation&lat=:lat&lng=:lng&radius=:radius' ).get({lat:location.lat,lng:location.lng,radius:radius});
      },
      getJobs: function() {
        return $resource('/ajax/api.cfm?api=job&function=getJobsAssignedtoWorkshop' ).get();
      },
      sendMechanicsJobNotifications: function(mechanics, jobs) {
        return $resource('/ajax/api.cfm?api=job&function=sendMechanicsJobNotifications&mechanics=:mechanics&jobs=:jobs' ).get({mechanics:mechanics.toString(),jobs:jobs.toString()});
      },
      addMechanic: addMechanic,
      removeAllMechanics: removeAllMechanics,
      getAllMechanics: getAllMechanics,
      addJob: addJob,
      removeAllJobs: removeAllJobs,
      getAllJobs: getAllJobs
    }
});


mechanicsearch.controller('SearchCtrl', ['$timeout', '$scope', '$window', '$location', '$routeParams', 'filterFilter', 'mechFactory', '$resource', '$element',

    function ($timeout, $scope, $window, $location, $routeParams, filterFilter, mechFactory, $resource, $element) {

        $scope.place = {};
        $scope.place.address = null;
        $scope.place.lat = null;
        $scope.place.lng = null;
        $scope.radius = 25;
        $scope.mechanics = [];
        $scope.selection = [];
        $scope.alert = null;
        $scope.showSearchPanel = true;

        //Helper method to get selected mechanics
        $scope.selectedMechanics = function selectedMechanics() {
          filterFilter($scope.mechanics, { selected: true })
        };

        //allow mechanic checkbox to select/deselect on click
        $scope.toggleMechanicSelect = function(mechanic) {
          mechanic.selected = !mechanic.selected;
        }

        $scope.goToJobListing = function() {
          $scope.showSearchPanel = false;
          mechFactory.removeAllMechanics();
          for( var i in $scope.selection ) {
            mechFactory.addMechanic($scope.selection[i]);
          }
          $scope.$emit('handleActiveJobsPanel');
        }

        // watch mechanics for changes
        $scope.$watch('mechanics|filter:{selected:true}', function (nv) {
         $scope.selection = nv.map(function (mechanic) {
           return mechanic.objectid;
         });
        }, true);

        //watch the returning google autocomplete details object
        $scope.$watch('details', function() {
          if( $scope.details !== undefined && $scope.details !== null ) {
            $scope.place.address = $scope.details.formatted_address;
            $scope.place.lat = $scope.details.geometry.location.lat();
            $scope.place.lng = $scope.details.geometry.location.lng();
          }
        });

        // watch the $scope.place data for changes
        $scope.$watchCollection('place', function() {
          if( $scope.place.lat !== null || $scope.place.lng !== null ) {
            $scope.getMechanics();
          }
        });

        $scope.$watch('radius', function() {
          if( Number.isInteger(parseInt($scope.radius))  ){
            $scope.getMechanics();
          }
        });

        $scope.setDirectiveFn = function(directiveFn) {
          $scope.directiveFn = directiveFn;
        };

        $scope.getMechanics = function() {
          mechFactory.getMechanics($scope.place, $scope.radius).$promise.then(
            function successfulResult (mechanicsData) {

              if (!mechanicsData || !mechanicsData.data.length){
                $scope.alert = 'Sorry, no mechanic found in "' + $scope.place.address + '" with radius of ' + $scope.radius + '.';
                $scope.mechanics = [];
                $scope.selection = [];
              } else {
                $scope.alert = mechanicsData.data.length + ' mechanic(s) found in "' + $scope.place.address + '" with radius of ' + $scope.radius + ' km.';
                $scope.mechanics = mechanicsData.data;
                $scope.selection = [];
              }

            }, function failedResult (err) {
              $scope.alert = err.message;
            });
        };

        //display panel once we have recieved the event
        $scope.$on('activateSearchPanel', function(event, args) {
          $scope.mechanics = [];
          $scope.selection = [];
          $scope.alert = null;
          $scope.showSearchPanel = true;
          $scope.place = {};
          $scope.radius = 25;
        });
    }
]);
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular-route.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular-resource.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCmN0htBqG3DGo04KKKzC9srgIrhP0Dq5o&libraries=places"></script>
  
  
<div id="mechanicsearch" data-ng-app="mechanicsearch">

        <div data-ng-controller="SearchCtrl" ng-show="showSearchPanel">
          <aside class="workshopsearch" >

              <form method="post" class="form-inline" role="form">
                <div class="row">
                      <div class="col-sm-6 form-group input-group-lg">
                          <input type="text" id="geoSearch" ng-model="autocomplete" class="form-control" ng-autocomplete options="{ types: 'geocode', country: 'au', watchEnter: true }" details="details" set-fn="setDirectiveFn(theDirFn)" />
                      </div>
                      <div class="col-sm-6 input-group input-group-lg">
                        <input type="text" class="form-control" name="radius" id="radius" placeholder="Radius" data-ng-model="radius">
                        <span class="input-group-btn"><button class="btn btn-go" ng-click="directiveFn()">Go</button</span>
                      </div>
                  </div>
              </form>
          </aside>
         </div>
        </div>
&#13;
&#13;
&#13;

}

1 个答案:

答案 0 :(得分:3)

为什么在element.val()绑定到输入时使用ngModel?为什么不使用scope.ngModel