2013-11-08 2 views
16

Я хотел бы сделать запрос к моему серверу в фильтре и вернуть результат моего запроса. Проблема заключается в том, что сервис $ http возвращает обещание, и это проблема.

На сегодняшнем вопрос я использовал $ таймаут и обещание углового в моей скрипке: my fiddle

В моем фильтре я использую $ таймаут с обещанием, но конечная цель состоит в том, чтобы использовать запрос HTTP:

myApp.filter('filterHello', function ($http,$timeout,$q) { 
return function (company_id) { 
    console.log("in the filter"); 
    var deferred = $q.defer(); 
    $timeout(function() { 
     deferred.resolve("ca marche"); 
    }, 2000);     
    return deferred.promise; 
}; 

});

Тогда на мой взгляд, я использую свой фильтр, который предполагают, чтобы отобразить «ча Marche» с задержкой 2 secondes, но это не работает:

<div ng-controller="MyCtrl"> 
    {{hello|filterHello}} 
</div> 

Вы можете видеть, что обратный фильтр ничего и что в фильтре есть бесконечный цикл из-за нулевого обещания, который я думаю.

Если вы не понимаете, почему я хочу использовать запрос http в фильтре, ответ прост. Например, у меня есть пользователь объекта с полями: email, name, company_id .. И у меня есть другая компания-объект с полями: name, createOn, ... Я бы хотел использовать фильтр, подобный этому, для отображения название компании пользователя:

{{user.company_id | ShowNameCompany}}

Итак, мне нужно сделать запрос http в фильтре моему контроллеру моей бэкэнда.

Я надеюсь, что кто-то может мне помочь.

+0

Post код, который вы пытались пожалуйста –

+0

ссылки вашей скрипки –

+4

Фильтров огнь МНОГО! Для достижения вашей цели должен быть более удобный метод измерения пропускной способности. –

ответ

16

Я думаю, что вы не должны использовать фильтры таким образом. Фильтры предназначены для преобразования входов на основе дополнительных параметров.

Проблема в том, что вы немедленно возвращаете обещание от функции фильтра. И это ничего, с чем может столкнуться Угловой в результате фильтра.

Поэтому мое предложение было бы это - получить результат первых, работать с фильтром на основе результата:

var app = angular.module("my.module"); 

app.controller("MyCtrl", ['$http', '$scope', function(http, scope) { 
    scope.hello = "foo"; 
    http.get('http://my.service.com').then(function(data) { 
    scope.filterParams = data; 
    }, function(err) { 
    scope.filterParams = undefined; 
    }); 
}]); 

app.filter("filterHello", function() { 
    return function(input, params) { 
    if(typeof params === "undefined") { 
     return ""; 
    } 
    //work with the params here 
    }; 
}); 

и в шаблоне:

<div ng-controller="MyCtrl"> 
    {{hello|filterHello:filterParams}} 
</div> 

Edit: Просто читать ваши объяснения , Для меня это было бы кандидатом на директиву:

app.directive("companyName", ['$http', function(http) { 
    return { 
    template: "<span>{{name}}</span>", 
    scope: { 
     companyId: "=" 
    }, 
    link: function(scope) { 
     http.get("http://my.service.com/companies/" + scope.id).then(function(result) { 
     scope.name = result.name; 
     }, function(err) { 
     scope.name = "unknown"; 
     }); 
    } 
    } 
}]); 

и в шаблоне:

<span company-name company-id="user.company_id"></span> 

Если у вас есть много компаний, вы должны предварительно загрузить имена (возможно, отправить их с первый ответ изначально?), так как вы будете слишком часто обманывать свой сервер запросами.

+0

Эй, Флориан. Это хорошая идея, чтобы создать директиву, проблема заключается в том, что я использую запрос http для получения пользователя, поэтому в моей директиве область companyId не определена. Мне нужно подождать, когда пользователь загрузится, но я не знаю, как ... Это имеет смысл? – FlavienBert

+1

Я просто исправляю эту проблему, используя ng-if = "user.company_id", подобный этому угловому исполнению, когда пользователь загружается. – FlavienBert

0

Или вы могли бы использовать фильтр с учетом состояния:

angular.module("app").filter('companyName', function($http) { 
     var cached = {}; 
     var apiUrl = 'http://my.service.com'; 
     function companyNameFilter(company_id) { 
      if (company_id) { 
       if (company_id in cached) { 
        // avoid returning a promise! 
        return typeof cached[company_id].then !== 'function' ? 
         cached[company_id] : undefined; 
       } else { 
        cached[company_id] = $http({ 
         method: 'GET', 
         url: apiUrl + company_id 
        }).success(function (companyName) { 
          cached[company_id] = companyName; 
         }); 
       } 
      } 
     } 
     companyNameFilter.$stateful = true; 
     return companyNameFilter; 
}) 

и использовать его так: {{company_id | companyName}}

Внимание: Функция companyNameFilter будет вызываться каждый переваривать цикл.

Кроме того, вам нужно будет выяснить способ сброса кеша, если он станет слишком большим.

См: https://glebbahmutov.com/blog/async-angular-filter/

И plunker (ссылка выше не будет отображать его, так вот прямая ссылка): http://plnkr.co/edit/EK2TYI1NZevojOFDpaOG?p=preview

0

Если вы должны сделать запрос HTTP внутри фильтра, как я нашел причина в последнее время, затем сделайте это, как показано ниже.

Обратите внимание, что Угловая команда не рекомендует использовать сохраняющих состояние фильтров, цитирую из их документации

строго не рекомендуется писать фильтры, с сохранением состояния, так как выполнение тех, которые не могут быть оптимизированы Угловое , который часто приводит к проблемам с производительностью. Многие фильтры с сохранением состояния могут быть преобразованными в фильтры без сохранения состояния, просто подвергая скрытое состояние модели и превращая ее в аргумент для фильтра.

Однако, если вы действительно должны написать с учетом состояния фильтра, вы должны отметить фильтр в $ отслеживанием состояния, что означает, что он будет выполнен один или более раз в течение каждого $ переваривать цикла. Stateful filters

Двигаясь по этой рекомендации, вот что вы должны сделать:

  1. Объявить свой фильтр таким образом, что он принимает объект области видимости, как это первый параметр: функция фильтра ($ HTTP) {

    return function (cached, type, productField) { 
         var key = type + '-' + productField; 
         var oDataFilter = 'Id eq \'' + productField + '\''; 
         var select = 'Id,Name'; 
         if (typeof cached[key] == 'undefined') { 
          $http({ 
           url: '//<endpoint>/resource.json?$select=' + select + '&$filter=' + oDataFilter 
           , method: 'GET' 
           , headers: { 
            Accept: 'application/json' 
           } 
          }).then(function (data) { 
           cached[key] = data.data.d.length > 0 ? data.data.d[0].Name : 'Not found'; 
          }); 
          cached[key] = 'Loading...'; 
         } 
         return cached[key]; 
        } 
    } 
    filter.$inject = ['$http']; 
    app.filter('myFilter', filter); 
    
  2. Определите переменную, которая будет доступна в пределах вашего шаблона. Я позвоню моему filterCache и назначит и пуст объект {}.

  3. Invoke фильтра изнутри шаблона, как это:

    <div ng-bind-template="{{filterCache|myFilter:firstParameter:secondParameter}}"></div>
Смежные вопросы