简体   繁体   中英

AngularJS + Rails: get a resource but stay on current page

I have a page with a button that will change the state of the resource on the server. Everything is wired up and working fine. But I had to resort to a server response that sent the browser "back" because I don't want to display a new template for the action url.

This seems like a typical thing to do: ask the server to do something, then get the current state of the resource and redisplay it in the current template without refetching the template.

The markup on the page is like this:

<a ng-href="/api/preference/{{video._id}}/add_to_watchlist" data-method="get">
    <i rel="tooltip" data-original-title="Add to watchlist" class="icon-3x action-icon
        icon-plus-sign" ng-class="{iconSelected : video.user_watchlist == 1}">
    </i>
</a>

This highlights the icon depending on the value of $scope.video.watchlist. When clicked it fires a custom action on the server to add the video being viewed to the current user's watchlist. The url created is /api/preference/{{video._id}}/add_to_watchlist, this fires the server controller, which does the right thing but instead of going to a template for /api/preference/{{video._id}}/add_to_watchlist the server responds by telling the client to go "back" in Rails this is redirect_to :back .

Clearly this is wrong. It works but refetches the entire page markup and data.

The AngularJS controller that loads the original data is here:

GuideControllers.controller('VideoDetailCtrl', ['$scope', 'Video',
    function($scope, Video) {
        var pattern = new RegExp( ".*/([0-9,a-f]*)", "gi" );
        //ugh, there must be a better way to get the id!
        $scope.video = Video.get({ id: pattern.exec( document.URL )[1] });
    }
]);

Here is the resource that gets the json

var VideoServices = angular.module('VideoServices', ['ngResource']);

VideoServices.factory('Video', ['$resource',
    function($resource){
        return $resource("/api/videos/:id", {id: "@id"}, {
            update: {method: "PUT"},
            query: {
                isArray: true,
                method: "GET",
                headers: {
                    "Accept": "application/json",
                    "X-Requested-With": "XMLHttpRequest"
                }
            },
            get: {
                isArray: false,
                method: "GET",
                headers: {
                    "Accept": "application/json",
                    "X-Requested-With": "XMLHttpRequest"
                }
            }
        });
    }
]);

Somehow I need to

  1. tell the server to add_to_watchlist without changing the browser URL
  2. trigger a refetch of the video json without reloading the template.

It seems like you're relying on routing to handle a model update on the server, instead of doing it through angular's $resource service. Here's a quick and dirty:

Instead of routing, call a function when the user clicks:

<a ng-click="addToWatchlist(video._id)">
<i rel="tooltip" data-original-title="Add to watchlist" class="icon-3x action-icon
    icon-plus-sign" ng-class="{iconSelected : video.user_watchlist == 1}">
</i>
</a>

Add the click handler function to your controller (I'm using $http here, but you would be better off adding a custom action to your Video resource). On the success callback you can reload the video. Or, better yet, you can return the video from the add_to_watchlist action.

Check out http://docs.angularjs.org/tutorial/step_07 which explains the $routeParams (to answer your comment about getting the video id).

GuideControllers.controller('VideoDetailCtrl', ['$scope', '$http', '$routeParams', 'Video',
    function($scope, $http, $routeParams, Video) {
        $scope.video = Video.get({ id: $routeParams.videoId });
        $scope.addToWatchlist = function(videoId) {
            $http.get('/api/preference/'+videoId+'/add_to_watchlist').success(function() {
                $scope.video = Video.get({ id: $routeParams.videoId });
            };
        };


    }
]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM