Angular $ resource - как использовать обещание?

Как я могу использовать обещание с $ resource?

Это моя служба,

     app.service("friendService",function( $resource, $q ) {

        // Return public API.
        return({
            addFriend: addFriend,
            updateFriend: updateFriend,
            getFriends: getFriends,
            removeFriend: removeFriend
        });

        function updateFriend( friend ) {

            var postData = { 
                id: friend.id,
                name: friend.name
            };

            var request = $resource("api/update.php", null,{
                update: { 
                    method:'PUT',
                    data:postData
                }
            });


            return( request.$promise.then( handleSuccess, handleError ) );
        }

Я получаю эту ошибку,

TypeError: request. $ Обещание не определено

Как правильно это сделать с помощью $ resource?


person laukok    schedule 07.11.2014    source источник
comment
Вы используете angular-resource, как $ http. Возможно, вам не следует использовать $ resource, поскольку кажется (по вашему URL-адресу) вы на самом деле не используете RESTful api.   -  person Tivie    schedule 07.11.2014
comment
Тогда каков правильный шаблон URL для RESTful api?   -  person laukok    schedule 07.11.2014
comment
Проверить мой отредактированный ответ   -  person Tivie    schedule 08.11.2014
comment
Спасибо за редактирование.   -  person laukok    schedule 08.11.2014


Ответы (4)


Меняться от

return( request.$promise.then( handleSuccess, handleError ) );

to

return request.update().$promise.then(handleSuccess, handleError);

Тем не менее, использовать $resource, как это, довольно неэффективно, и при этом не использовать никаких преимуществ. Лучше заменить на $http.

person Buu Nguyen    schedule 07.11.2014
comment
попробовал и получил вот это - Error: friendService.updateFriend(...).update is not a function - person laukok; 07.11.2014
comment
Я пробовал, и у меня не было этой ошибки. Вот плункер: plnkr.co/edit/gKS1TdHaL3Bz1qOTekXg?p=preview. - person Buu Nguyen; 07.11.2014
comment
Исправлено, спасибо. Я должен использовать .$promise.then(handleSuccess, handleError); в службе, но в контроллере. - person laukok; 07.11.2014
comment
Рад, что проблема исправлена. Если этот ответ указал вам правильное направление, примите его. - person Buu Nguyen; 07.11.2014

Вы должны упростить свой сервис, чтобы на самом деле БЫТЬ ресурсом $

app.factory('friendService', [ '$resource', function($resource) {
    return $resource('/api/friends/:id', null, {
        'update' : {
            method : 'PUT'
        }
    });
} ]);

Это автоматически обеспечивает следующие конечные точки (что на самом деле здорово в $ resource):

{ 'get':    {method:'GET'},
  'save':   {method:'POST'},
  'query':  {method:'GET', isArray:true},
  'remove': {method:'DELETE'},
  'delete': {method:'DELETE'}
};

Вот несколько примеров использования:

friendService.query(success, error); // GET /friends
friendService.get({ id : "exampleId" }, success, error); // GET /friends/exampleId
friendService.save({/* no params */}, friendObjectWithId, success, error); // POST /friends/idTakenFromObject
friendService.delete({ id : "exampleId" }, {}, success, error); // DELETE /friends/exampleId
friendService.update({/* no params */}, friendObjectWithId, success, error); // PUT /friends/idTakenFromObject

Итак, как описывает эта строка документации, вам не нужно обещание $ чтобы указать обратные вызовы:

не-GET действия "класса": Resource.action ([параметры], postData, [успех], [ошибка])

Итак, вы можете просто сделать что-то вроде этого:

friendService.update({}, friendObject, successHandler, errorHandler)
person Jonas    schedule 07.11.2014

Короткий ответ:

Я думаю, вы неправильно понимаете, что такое $resource, поскольку вы пытаетесь использовать его так же, как использовали бы $http.

$resource - это оболочка вокруг $http, обеспечивающая объектно-ориентированный CRUD-способ взаимодействия с RESTful api. (DOCS хорошо объяснит это и предоставит хорошие примеры)

Судя по вашему URL, я не думаю, что вы на самом деле используете REST api, поэтому, вероятно, было бы лучше использовать службу $http вместо использования службы $ resource.

Тем не менее, вот рабочая скрипка.


Ресурсы и REST API

Ресурс в контексте angular соответствует ресурсу в контексте REST, поэтому он будет ожидать, что ваш веб-сервис будет вести себя как приложение RESTful. Чтобы объяснить это дальше, давайте возьмем вашего друга в качестве примера ... (я буду переделывать ваши URL-адреса, чтобы они лучше соответствовали REST API)

Определение API

Возьмите следующую схему, совместимую с REST + CRUD (для ресурса Friend)

Resource            URI             Methods allowed
Friend Collection   api/friend      GET, POST
Friend              api/friend/:id  GET, PUT

Основная идея здесь заключается в том, что каждый ресурс однозначно представлен URI (это фактически определение URI: - ›Uniform Resource Identifier), а метод HTTP (Verb) используется для определения действие, которое будет выполнено на указанном Ресурсе.

Конечно, REST - это гораздо больше, и я предлагаю вам прочитать этот ТАК POST или эту забавную статью или даже диссертация Роя Филдинга < / a> (парень, который придумал REST), которые объясняют концепцию намного лучше, чем я когда-либо мог надеяться.


Структура URL

Этот вопрос подвержен горячим спорам, и вы можете прочитать некоторые интересные моменты здесь, в этом Сообщение SO и статья Роя Филдинга, частично посвященная этому вопросу. Подводя итог, REST не требует чистых URL-адресов. На самом деле, это не требует НИКАКОЙ семантически логической структуры URL.

API REST должны быть управляемыми гипертекстом, то есть с учетом точки входа (URL) API должен быть самоочевидным, чтобы клиент мог самостоятельно обнаруживать ресурсы и отношения с типом ресурсов, заданным типами мультимедиа. Это означает, что если URL-адрес изменится, API не сломается !!

Итак, с практической точки зрения это могут быть действительные:

Home                 /
Friend Collection    /foo
Friend Resource 1    /bar
Friend Resource 2    /baz

Также может быть действительным:

Home                index.php
Friend Collection   index.php?q=api/friend
Friend Resource 1   index.php?q=api/friend/1
Friend Resource 2   index.php?q=api/friend/2

Или его двоюродный брат, использующий mod_reqrite для создания чистых URL-адресов, может быть действительным

Home                /
Friend Collection   /api/friend
Friend Resource 1   /api/friend/1
Friend Resource 2   /api/friend/1

или даже это может быть действительным ...

Home                /index.php
Friend Collection   /friend.php
Friend Resource 1   /friend_1.php
Friend Resource 2   /friend_2.php

Сервер ни в коем случае не обязан следовать какому-либо шаблону. Однако это не означает, что вы не должны придерживаться структуры, в основном для целей SEO (или для удобства чтения). И в последнем примере может быть сложно разработать разумный веб-сервис, который полагается на отдельные сценарии для каждого отдельного ресурса. (вы можете не нарушать принципы REST, но вы, вероятно, нарушите некоторые базовые правила программирования, такие как DRY ...)

Кроме того, angular-resource (отчасти) самоуверенно относится к структуре URL-адресов. Это не абсолютное требование, но ...

Что касается вашего конкретного вопроса, да, вам понадобится mod_rewrite в соответствии с примером, который я вам дал. Но вам не нужен mod_rewrite для создания API, совместимого с REST.


Использование модуля angular-resource

Теперь, когда наша схема API настроена и следует принципам REST + CRUD, мы можем использовать весь потенциал модуля angular-resource.

Мы можем создать клиентское представление (интерфейс) Друга.

//Custom actions
var actions = {
    update: {
        method: 'PUT'
    }
}

var friendUrl = "/api/friend/:id"; // should be obtained by inspecting the API iteself, usually the parent collection. 
var Friend = $resource(friendUrl, {id: '@id'}, actions);

Чтобы найти друга, мы отправляем запрос GET (и указываем его id);

Friend.get({id: 1}).$promise.then(
    function (response) {
        //console.log(response);
    }
);

Запросы DELETE и PUT (которые мы создали и назвали update) в основном одно и то же. $ resource также поддерживает получение коллекций с помощью запроса метода объекта. Вы можете использовать это, чтобы получить коллекцию друзей.

Обратите внимание, что для простоты я использую жестко заданный URL

person Tivie    schedule 07.11.2014
comment
Спасибо. Но каков же тогда правильный шаблон URL для RESTful api? - person laukok; 07.11.2014
comment
Еще раз спасибо за обновление. Но тогда разве нам не нужно устанавливать mod_rewrite в .htaccess для такого URL-адреса "/api/friend/:id", иначе как он будет указывать на мой php-файл для обработки запроса? - person laukok; 08.11.2014
comment
@tealou, чтобы соответствовать моему примеру, да, но URL-адреса preety не требуются для REST! - person Tivie; 08.11.2014
comment
but pretty URLs are not required by REST если это не требуется, то как мы можем заставить REST работать? Как мы собираемся отправлять данные в наш REST API без перезаписи URL ?? - person laukok; 08.11.2014
comment
@tealou Что ты имеешь в виду? Вы отправляете данные обычным способом в теле запроса. mod_rewrite - это механизм перезаписи apache для перезаписи URL-адресов на лету. Это не имеет ничего общего с тем, как данные отправляются и обрабатываются. - person Tivie; 09.11.2014
comment
если я отправлю /api/friend/1, я получу файл, которого нет в консоли моего браузера, без перезаписи URL-адреса в .htaccess. - person laukok; 09.11.2014
comment
@tealou Ах да, конечно URL должен быть действующим. Я хотел сказать следующее: REST - это не очень красивые URL. Вам не нужны красивые URL-адреса, такие как /api/friend/1, для RESTful. Например, у вас может быть файл с именем friend.php внутри папки с именем api. А затем используйте URL example.com/api/friend.php?id=1. - person Tivie; 09.11.2014
comment
тогда все это имеет смысл, лол, конечно, REST - это не красивые URL-адреса: D - person laukok; 09.11.2014
comment
@tealou Извини. Я неправильно понял, о чем вы спрашиваете, и немного переборщил с моим объяснением = P - person Tivie; 09.11.2014
comment
Не волнуйся, Тиви. Я ценю ваше объяснение, и оно обостряет мое понимание REST. Меня это всегда смущало. Спасибо! ;-) - person laukok; 09.11.2014

запрос просто настраивает вашу конечную точку. На самом деле вам нужно вызвать какой-то метод, например request.get({id: 1}).$promise; или request.query({term: 'test'}).$promise;

person Nat Wallbank    schedule 07.11.2014
comment
если я собираюсь перейти на это var request = $resource("api/update.php").save({}, postData).$promise.then( handleSuccess, handleError ); да, это работает, но как я могу изменить метод .save() на method:'PUT'? по умолчанию .save() отправляет POST. - person laukok; 07.11.2014
comment
Просто вызовите определенный вами пользовательский метод .update (), который выполняет PUT. - person Nat Wallbank; 07.11.2014
comment
Вы можете сначала определить запрос, как вы это делали в своем примере (с помощью пользовательского метода обновления). Затем просто выполните request.update ({params}, data). $ Promise; - person Nat Wallbank; 07.11.2014
comment
пробовал и все равно получаю эту ошибку - Error: $resource(...).update is not a function - person laukok; 07.11.2014
comment
Исправлено, спасибо. Я должен использовать .$promise.then(handleSuccess, handleError); в службе, но в контроллере. - person laukok; 07.11.2014