Angularjs:指令不更新视图绑定范围

时间:2016-06-27 01:01:45

标签: angularjs angularjs-directive

我有一个指令,负责向服务器请求数据并定义要在视图上显示的范围属性,该指令还具有创建新请求的功能以及是否响应了新请求,视图应该更新为新数据..但问题依赖于第二步,即更新视图

所以指令的构造如下:

app.directive("restBatch", ["restFactory", "utilityFactory", function($rest, $util){
    function batch(uri, cb){
        $rest.batch(uri)
            .then(function(data){
                cb(data);
            });
    };

    return {
        restrict: "A",
        controller: ["$scope", function($scope){
            //Create a new request and update the view with the new data
            $scope.$search = function(data){
                var uri = this.$uri + "?q" + $util.querySearch(data);

                batch(uri, function(data){
                    $scope[this.$name] = $scope.$inline ? $util.group(data, $scope.$inline) : data;
                });
            }
        }],
        link: function(scope, element, attr){
            var call = $util.parseAlias(attr.restBatch || scope.$data.$uri);
            var uri  = $util.resolveUri(call.name, attr.uid ? attr.uid : null);
            var name = call.alias ? call.alias : "$batch";

            scope.$inline = attr.restInline || null;

            batch(uri, function(data){
                scope[name] = scope.$inline ? $util.group(data, scope.$inline) : data;
                scope.$uri = uri;
                scope.$name = name;
            });
        }
    }
}]);

link上的所有内容都能正常运行,但问题发生在范围内的$search上,视图未更新,即使我使用$apply(),也会抛出$digest错误。在$search内记录范围会显示新数据,但视图未更新

如果需要视图模板来查看它是如何工作的,那么它是:

<div layout="column" layout-fill rest-batch rest-inline="3">
    <div layout="row">
        <div flex="5"></div>
        <div flex="10" layout layout-align="center center">
            <md-button class="md-warn md-raised" ui-sref="plans.create">Create</md-button>
        </div> 
        <div flex="70" layout layout-align="center center">
            <md-button ui-sref="plans">Plans</md-button>
            <md-button ui-sref="plans.workouts">Workouts</md-button>
            <md-button ui-sref="plans.meals">Meals</md-button>
        </div>
        <md-input-container flex class="search">
            <label>Search Plans</label>
            <input ng-model="searchText" ng-keyup="$search(searchText)">
        </md-input-container>
    </div>
    <md-content flex ui-view="plans"></md-content>
</div>

更新 我将添加其他工厂和服务,以清除有关其在指令中使用的原因的所有问题

restFactory:

app.factory("restFactory", ["Restangular", "userService", "$q", "utilityFactory", function($rest, $user, $q, $util){
    return {
        batch: function(uri, params){
            return $rest.all(params ? $util.parseParams(uri, params) : uri).getList({access_token: $user.getToken()});
        },
        detail: function(uri, id){
            return $rest.one(uri, id).get({access_token: $user.getToken()});
        },
        severalDetail: function(uri){
            var deferred = $q.defer();
            var self = this;

            var collection = [];

            self.batch(uri).then(function(batch){
                for (var i = 0; i < batch.length; i++) {
                    self.detail(uri, batch[i].id).then(function(data){
                        collection.push(data);

                        if(batch.length == collection.length){
                            deferred.resolve(collection);
                        }
                    });
                }
            });

            return deferred.promise;
        }
    };

    function parseUri(uri){
        var regex = /\w+\/+\:+\w{2,}/g;

        var matches = uri.match(regex);

        matches.forEach(function(element, index){
            var res = resolveResource(element);

            if(res.resource == 'accounts'){
                res.value = $user.getId();
            }
        });
    }

    function resolveResource(uri){
        var arr = uri.split('/');

        return {
            resource: arr[0],
            parameter: arr[1] || null
        };
    }
}]);

utilityFactory:

app.factory("utilityFactory", ["userService","$httpParamSerializerJQLike", function($user, $serial){
    return {
        group: function(content, inline){
            var arrExt = [], index = 0;

            if(content.length <= inline){
                arrExt.push(content);
            }

            else{
                for(i = 0; i <= content.length / inline; i++){
                    var arrTemp = [];

                    for(e = 1; e <= inline; e++){
                        if(content[index])
                            arrTemp.push(content[index]);

                        index++;
                    }

                    arrExt.push(arrTemp);
                }
            }


            return arrExt;
        },
        parseAlias: function(exp){
            var regex = /\s+as\s+/;

            var obj = {
                name: null,
                alias: null
            };

            if(exp.match(regex)){
                var data = exp.split(regex);
                obj.alias = data[1];
                obj.name = data[0];
            }

            else{
                obj.name = exp;
            }

            return obj;
        },
        resolveUri: function(uri, id){
            return uri.replace("@id", id || $user.getId());
        },
        parseParams: function(uri, params){
            if(Object.prototype.toString.call(params) == "[object Object]"){
                for(p in params){
                    var param = ":" + p;

                    uri.replace(param, params[p]);
                }
            }

            return this.resolveUri(uri, params["@id"] || null);
        },
        querySearch: function(query){
            return $serial(query);
        }
    }
}])

userService

app.service('userService', ['$rootScope', '$resource', '$window', '$cookies', 'Restangular', function($rootScope, $resource, $window, $cookies, $rest){
    var self = this;
    var apiHost = 'http://' + $window.location.hostname + ':3000';

    /**
     * User cache data to access globally
     */
    self._data = {
        id: null,
        username: null,
        email: null,
        accessToken: null
    };

    /**
     * All messages for user
     */
    self._messages = {
        login: {
            error: {
                credentials: 'name/email or password is invalid.',
                accessToken: 'Provided token is invalid'
            }
        },
        register: {
            error: {
                credentials: 'Username is already taken.'
            },
            success: {
                credentials: 'User successfully created.'
            }
        },
        main: {
            error: {
                connection: 'Service error, please try again later.',
            }
        }
    };

    self.isGuest = true;

    /**
     * Populate all necesary data user cache
     * @param  {Object} data The data to populate
     */
    self._populate = function(data){
        self._data.id = data.id;
        self._data.username = data.username;
        self._data.email = data.user_email;
        self._accessToken = data.access_token;
    };

    /**
     * Get the name of the user from user cache
     * @return {String} The name of the user
     */
    self.getName = function(){
        return self._data.username;
    };

    /**
     * Get the id of the user from user cache
     * @return {Integer} The id of the user
     */
    self.getId = function(){
        return self._data.id;
    };

    /**
     * Get the access token of the current logged user
     * @return {String} Access token data
     */
    self.getToken = function(){
        return self._accessToken;
    };

    /**
     * Register a user with the given credentials and returns the result
     * @param  {Object}   credentials The credentials of the user
     * @param  {Function} callback    The callback to run when tries to register
     */
    self.register = function(credentials, callback){
        $rest.all('accounts').post(credentials).then(function(data){
            if(!data.passed){
                callback({
                    passed: false,
                    message: self._messages.register.error.credentials
                });
            }

            else{
                self.login(credentials, function(){});

                callback({
                    passed: true,
                    message: self._messages.register.success.credentials
                });
            }
        });
    };

    /**
     * Login the user with the given credentials and returns the result
     * @param  {Object}   credentials The credentials to send to server and login
     * @param  {Function} callback    The result of the server response
     */
    self.login = function(credentials, callback){
        $rest.all('accounts/login').post(credentials).then(function(data){
            var result = {
                success: false,
                error: null
            };

            if(typeof data.id !== "undefined"){
                self._populate(data);

                if(credentials.remember){
                    self.storeAccessToken(data.access_token);
                }

                self.isGuest = false;
                result.success = true;

                $rootScope.$broadcast('userLogged', (typeof credentials.token !== 'undefined'));
            }

            else{

                // Find if token was provided
                for(k in credentials){
                    // Return error message for token provided
                    if(k == 'token'){
                        result.error = self._messages.login.error.accessToken;
                        break;
                    }
                }

                // Return error message for invalid credentials
                if(!result.error)
                    result.error = self._messages.login.error.credentials;
            }

            callback(result.success, result.error);
        })
        .catch(function(err){
            callback(false, self._messages.main.error.connection);
        });
    };

    /**
     * Logs out the user by removing cache data and cookie data
     * @return {boolean} Either if operation was successfull or not
     */
    self.logout = function(){
        if(!self.isGuest){
            self.removeToken();

            for(prop in self._data)
                self._data[prop] = null;

            return true;
        }

        return false;
    }

    /**
     * Store the access token of the user for auto re-login
     * @param {String} token The hash of the token to store in cookie
     * @return {void}
     */
    self.storeAccessToken = function(token){
        var time = new Date();

        $cookies.put('accessToken', token, {
            expires: new Date(time.getFullYear(), time.getMonth() + 1, time.getDate())
        });
    };

    /**
     * Remove the token stored in cookies if exists
     * @return {void}
     */
    self.removeToken = function(){
        if(self.hasToken)
            $cookies.remove('accessToken');
    };

    /**
     * Logs the user with a token stored in cookies
     * @param {function} 
     * @return {void}
     */
    self.logByToken = function(callback){
        if(self.hasToken()){
            self.login({token: $cookies.get('accessToken')}, function(success, error){
                callback(success, error);
            });
        }

        else
            callback(false, self._messages.login.error.accessToken);
    }

    /**
     * Check if client has token to access
     * @return {void}
     */
    self.hasToken = function(){
        if($cookies.get('accessToken'))
            return true;

        return false;
    }
}]);

0 个答案:

没有答案