AngularJS ile $ http zaman uyumlu arama nasıl yapılır


132

AngularJS ile eşzamanlı arama yapmanın herhangi bir yolu var mı?

AngularJS belgeleri, bazı temel şeyleri anlamak için çok açık veya kapsamlı değildir.

HİZMETTE:

myService.getByID = function (id) {
    var retval = null;

    $http({
        url: "/CO/api/products/" + id,
        method: "GET"
    }).success(function (data, status, headers, config) {

        retval = data.Data;

    });

    return retval;
}

Eşzamansız davranışla nasıl başa çıkılacağıyla ilgili bazı fikirler için groups.google.com/d/topic/angular/qagzXXhS_VI/discussion adresine de bakın : olaylar, $ watch, sunucu tarafında önyükleme, $ http'den döndürülen sözü kullanın.
Mark Rajcok

1
Asenkron her zaman daha iyidir, özellikle de vaatleriniz olduğunda.
Andrew Joslin

Çoğu zaman senkronize aramalardan kaçınabilirsiniz. $ Resource'un nasıl çalıştığını görün stackoverflow.com/questions/11966252/… .
honzajde

3
@AndrewJoslin Asenkron, sipariş edilen teslimat gerektiğinde daha kötüdür.
Stijn Van Antwerpen

Yanıtlar:


113

Şu an değil. Eğer varsa (zaman 2012 Ekim bu noktadan) kaynak koduna bakabilir , sen XHR açıkken çağrısı aslında (Üçüncü parametre doğrudur) asenkron olarak kodlanmış olduğunu göreceksiniz:

 xhr.open(method, url, true);

Eşzamanlı aramalar yapan kendi hizmetinizi yazmanız gerekir. Genelde bu, JavaScript çalıştırmanın doğası nedeniyle genellikle yapmak isteyeceğiniz bir şey değildir, sonunda diğer her şeyi engelleyeceksiniz.

... ama .. diğer her şeyi engellemek gerçekten isteniyorsa, belki vaatlere ve $ q hizmetine bakmalısınız . Bir dizi eşzamansız eylem tamamlanana kadar beklemenize ve ardından hepsi tamamlandığında bir şeyler yürütmenize olanak tanır. Kullanım durumunuzun ne olduğunu bilmiyorum ama bu bir göz atmaya değer olabilir.

Bunun dışında, kendinizinkini atacaksanız, senkronize ve asenkron ajax çağrılarının nasıl yapılacağı hakkında daha fazla bilgiyi burada bulabilirsiniz .

Umarım yardımcı olur.


12
$ Q hizmetini kullanarak başarmak için lütfen pasajı kodlayabilir misiniz? Birçok seçeneği denedim ama eşzamansız bir şekilde çalışıyor.
Venkat

1
Bunun mantıklı olabileceği yerler vardır, örneğin, kullanıcı tarayıcıyı kapattığında (yüklemeden önce), kaydetmek istiyorsanız, bir senkronizasyon isteği göndermeniz gerekir, başka bir seçenek, bir iletişim kutusu iptalini gösterip ardından pencereyi yeniden başlatmaktır.
Braulio

2
@Venkat: Bunun geç bir cevap olduğunu biliyorum, ancak cevapta söylediğim gibi, çağrı her zaman "eşzamansız" olacaktır, cevabı bekletmek için $ q kullanmanız ve ardından mantığınızı .then(callback). gibi bir şey: doSomething(); $http.get('/a/thing').then(doEverythingElse);.
Ben Lesh


1
@BenLesh Ayırdığınız zamanı veya birisinin koyduğu zamanı takdir etmiyorum. Cevabınıza oy vermekte ve bir örnek sağlanırsa bana yardımcı olacağını söylemekte özgürüm. Cevabınızı gördüm, bana yardımcı olmadı, bu yüzden oy verdim ve sekmeyi kapattım ve bana daha faydalı olacak bir cevap bulmaya çalışmak için Google'a geri döndüm. Birisi cevabınızı olumsuz oyladığında ve size nasıl geliştirilebileceğini söylediğinde bu dünyanın sonu değil. Neden diye bir yorum bırakmadan red oylamamı tercih eder miydiniz? Sadece dürüst olmak.
devre

12

Google maps autocomplete ile entegre bir fabrika ile çalıştım ve verilen sözler, umarım hizmet edersiniz.

http://jsfiddle.net/the_pianist2/vL9nkfe3/1/

autocompleteService hizmetini fabrikadan önce $ http incuida ile bu istekle değiştirmeniz yeterlidir.

app.factory('Autocomplete', function($q, $http) {

ve ile $ http isteği

 var deferred = $q.defer();
 $http.get('urlExample').
success(function(data, status, headers, config) {
     deferred.resolve(data);
}).
error(function(data, status, headers, config) {
     deferred.reject(status);
});
 return deferred.promise;

<div ng-app="myApp">
  <div ng-controller="myController">
  <input type="text" ng-model="search"></input>
  <div class="bs-example">
     <table class="table" >
        <thead>
           <tr>
              <th>#</th>
              <th>Description</th>
           </tr>
        </thead>
        <tbody>
           <tr ng-repeat="direction in directions">
              <td>{{$index}}</td>
              <td>{{direction.description}}</td>
           </tr>
        </tbody>
     </table>
  </div>

'use strict';
 var app = angular.module('myApp', []);

  app.factory('Autocomplete', function($q) {
    var get = function(search) {
    var deferred = $q.defer();
    var autocompleteService = new google.maps.places.AutocompleteService();
    autocompleteService.getPlacePredictions({
        input: search,
        types: ['geocode'],
        componentRestrictions: {
            country: 'ES'
        }
    }, function(predictions, status) {
        if (status == google.maps.places.PlacesServiceStatus.OK) {
            deferred.resolve(predictions);
        } else {
            deferred.reject(status);
        }
    });
    return deferred.promise;
};

return {
    get: get
};
});

app.controller('myController', function($scope, Autocomplete) {
$scope.$watch('search', function(newValue, oldValue) {
    var promesa = Autocomplete.get(newValue);
    promesa.then(function(value) {
        $scope.directions = value;
    }, function(reason) {
        $scope.error = reason;
    });
 });

});

sorunun kendisi şu soruya yöneltilecek:

deferred.resolve(varResult); 

İyi iş çıkardığında ve istek:

deferred.reject(error); 

bir hata olduğunda ve sonra:

return deferred.promise;

5
var EmployeeController = ["$scope", "EmployeeService",
        function ($scope, EmployeeService) {
            $scope.Employee = {};
            $scope.Save = function (Employee) {                
                if ($scope.EmployeeForm.$valid) {
                    EmployeeService
                        .Save(Employee)
                        .then(function (response) {
                            if (response.HasError) {
                                $scope.HasError = response.HasError;
                                $scope.ErrorMessage = response.ResponseMessage;
                            } else {

                            }
                        })
                        .catch(function (response) {

                        });
                }
            }
        }]


var EmployeeService = ["$http", "$q",
            function ($http, $q) {
                var self = this;

                self.Save = function (employee) {
                    var deferred = $q.defer();                
                    $http
                        .post("/api/EmployeeApi/Create", angular.toJson(employee))
                        .success(function (response, status, headers, config) {
                            deferred.resolve(response, status, headers, config);
                        })
                        .error(function (response, status, headers, config) {
                            deferred.reject(response, status, headers, config);
                        });

                    return deferred.promise;
                };

4

Son zamanlarda, sayfanın yeniden yüklenmesiyle tetiklenen $ http çağrılarına yapmak istediğim bir durumla karşılaştım. Benim kullandığım çözüm:

  1. İki aramayı işlevlere sığdırın
  2. İkinci $ http çağrısını bir geri arama olarak ikinci işleve geçirin
  3. Apon .success içindeki ikinci işlevi çağırın

Ya n kere sunucuyu çağıran bir for döngüsü ise.
mithun

2

Eşzamansız olarak yapmanın ve her şeyi normalde yaptığınız gibi yönetmenin bir yolu. Her şey hala paylaşılıyor. Güncellenmesini istediğiniz nesneye bir referans alırsınız. Bunu hizmetinizde her güncellediğinizde, bir sözü izlemek veya iade etmek zorunda kalmadan dünya çapında güncellenir. Bu gerçekten güzel, çünkü altta yatan nesneyi yeniden bağlama gerekmeden hizmetin içinden güncelleyebilirsiniz. Angular'ı kullanılması gerektiği şekilde kullanmak. $ Http.get / post'u zaman uyumlu hale getirmenin muhtemelen kötü bir fikir olduğunu düşünüyorum. Komut dosyasında gözle görülür bir gecikme yaşarsınız.

app.factory('AssessmentSettingsService', ['$http', function($http) {
    //assessment is what I want to keep updating
    var settings = { assessment: null };

    return {
        getSettings: function () {
             //return settings so I can keep updating assessment and the
             //reference to settings will stay in tact
             return settings;
        },
        updateAssessment: function () {
            $http.get('/assessment/api/get/' + scan.assessmentId).success(function(response) {
                //I don't have to return a thing.  I just set the object.
                settings.assessment = response;
            });
        }
    };
}]);

    ...
        controller: ['$scope', '$http', 'AssessmentSettingsService', function ($scope, as) {
            $scope.settings = as.getSettings();
            //Look.  I can even update after I've already grabbed the object
            as.updateAssessment();

Ve bir görünümde bir yerde:

<h1>{{settings.assessment.title}}</h1>

0

XHR senkronizasyonundan beri önerilmemektedir, o güvenmek en iyisidir. Senkronizasyon POST isteği yapmanız gerekiyorsa, bir form gönderisini simüle etmek için bir hizmetin içindeki aşağıdaki yardımcıları kullanabilirsiniz.

Belirtilen URL'ye gönderilen gizli girişlere sahip bir form oluşturarak çalışır.

//Helper to create a hidden input
function createInput(name, value) {
  return angular
    .element('<input/>')
    .attr('type', 'hidden')
    .attr('name', name)
    .val(value);
}

//Post data
function post(url, data, params) {

    //Ensure data and params are an object
    data = data || {};
    params = params || {};

    //Serialize params
    const serialized = $httpParamSerializer(params);
    const query = serialized ? `?${serialized}` : '';

    //Create form
    const $form = angular
        .element('<form/>')
        .attr('action', `${url}${query}`)
        .attr('enctype', 'application/x-www-form-urlencoded')
        .attr('method', 'post');

    //Create hidden input data
    for (const key in data) {
        if (data.hasOwnProperty(key)) {
            const value = data[key];
            if (Array.isArray(value)) {
                for (const val of value) {
                    const $input = createInput(`${key}[]`, val);
                    $form.append($input);
                }
            }
            else {
                const $input = createInput(key, value);
                $form.append($input);
            }
        }
    }

    //Append form to body and submit
    angular.element(document).find('body').append($form);
    $form[0].submit();
    $form.remove();
}

İhtiyaçlarınız için gerektiği gibi değiştirin.


-4

Aramanızı bir Promise.all()yöntemle sarmalamaya ne dersiniz?

Promise.all([$http.get(url).then(function(result){....}, function(error){....}])

MDN'ye göre

Promise.all tüm yerine getirmeleri (veya ilk reddi) bekler


Neden bahsediyorsun? sorunun birden fazla
vaatle

Bir veya daha fazla sözün tamamlanmasını bekleyecek!
Manjit Dosanjh

nasıl çalıştığını görmek için bunu kullandın mı? Promise.all başka bir söz verir, eşzamansız senkronizasyon çağrılarına dönüştürmez
Ovidiu Dolha,

Hmm ... Görünüşe göre MDN belgeleri belirsiz olabilir ... Aslında belgelerinde belirtildiği gibi BEKLEMEZ.
Manjit Dosanjh

SO'ya hoş geldiniz. Kaliteli bir yanıt sağlamak için lütfen bu nasıl yanıtlanacağını okuyun.
thewaywere
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.