资讯专栏INFORMATION COLUMN

使用AngularJS构建应用时遇到的问题及解决方案(版本为1.3.9)

cuieney / 2438人阅读

摘要:最近在公司使用用完成了一个项目,在此记录一下过程中遇到的问题及解决方案。其他两种方法可参考站内文章控制器如何通信结语以上为我在编写一个应用时遇到的问题及解决方案,记录并分享出来,欢迎大家指正

最近在公司使用用AngularJS(1.3.9)完成了一个项目,在此记录一下过程中遇到的问题及解决方案。

使用$http服务发送ajax请求时后端无法判断请求是XMLHttpRequest

问题及场景
有时候后端会读取请求中headerX-Requested-With字段判断前端的请求是否为异步请求XMLHttpRequest,在使用$http服务发送请求时后端却判断为false

原因
"X-Requested-With" : "XMLHttpRequest"并不属于标准的header内容,因此Angular不会在header中默认设置该字段。

解决方案
手动在$httpProvider中设置该字段,代码如下:

    $httpProvider.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";

note:
可以创建一个公用服务,在配置方法做这个修改,公用服务注入到每个module里就一劳永逸了。

使用$http.post()方法参数类型不正确

问题及场景
在angular中,使用$http.post()方法提交数据时,发现所带参数并非Form Data,而是JSON对象,导致服务器无法使用一般方法正确获取参数,而使用jQuery的$.post()方法却可以正确获取。

原因
两者的post对header的处理有所不同,jQuery会把作为JSON对象的myData序列化,例如:

    var myData = { a : 1, b : 2 };
    // jQuery在post数据之前会把myData转换成字符串:"a=1&b=2"

angular显然没做这个处理。

解决方案
修改Angular的$httpProvider的默认处理,代码如下:

    $httpProvider.defaults.transformRequest = function(obj){
        var str = [];
        for(var p in obj) {
            str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
        }
        return str.join("&");
    };

    $httpProvider.defaults.headers.post = {
        "Content-Type": "application/x-www-form-urlencoded"
    };

note:
同样应该在公用服务中做此修改。

调用$scope.$apply(fn)更新视图时报错$rootScope:inprog

问题及场景
在更新$scope上的model数据时,如果是在digest监听外,会发现视图并没有自动更新,于是手动调用$scope.$apply(fn)方法通知视图进行更新,却发现有时候会报错$rootScope:inprog

原因
该错误原因是在进程当中$scope.$apply(fn)正在执行,不能在此基础上重复调用该方法。

解决方案
可以在调用该方法时做一个安全检测,封装代码如下:

    $scope.safeApply = function(fn) {
        var phase = this.$root.$$phase;
        if (phase === "$apply" || phase === "$digest") {
            if (fn && (typeof(fn) === "function")) {
                fn();
            }
        } else {
            this.$apply(fn);
        }
    };

note:
$$phase变量是scope中的一个内部属性,如果为null或者undefined则说明进程中没有$apply方法在运行,则可以直接调用,否则直接执行入参方法。

添加统一拦截器对ajax的请求或返回做处理

问题及场景
我遇到的场景是在发送异步请求时,后端会先判断用户是否已经登录,如果未登录则会在responseheader中添加一个redirecturl字段,前端读取该字段控制页面跳转到该url,我首先想到的解决方案就是前端需要做一个统一拦截器,对所有异步请求的response进行拦截。

解决方案
通过看Angular中$httpProvider部分的源码注释,发现了拦截器的几种写法,我选择的写法源码注释如下:

    *   // register the interceptor as a service
    *   $provide.factory("myHttpInterceptor", function($q, dependency1, dependency2) {
    *     return {
    *       // optional method
    *       "request": function(config) {
    *         // do something on success
    *         return config;
    *       },
    *
    *       // optional method
    *      "requestError": function(rejection) {
    *         // do something on error
    *         if (canRecover(rejection)) {
    *           return responseOrNewPromise
    *         }
    *         return $q.reject(rejection);
    *       },
    *       // optional method
    *       "response": function(response) {
    *         // do something on success
    *         return response;
    *       },
    *
    *       // optional method
    *      "responseError": function(rejection) {
    *         // do something on error
    *         if (canRecover(rejection)) {
    *           return responseOrNewPromise
    *         }
    *         return $q.reject(rejection);
    *       }
    *     };
    *   });
    *   $httpProvider.interceptors.push("myHttpInterceptor");

我拦截response的代码如下:

    commonService.factory("redirectInterceptor", function(){
        return {
            "response": function(response) {
                if(response.headers().redirecturl) {
                    window.location.href = response.headers().redirecturl;
                }
                return response;
            }
        };
    });

    $httpProvider.interceptors.push("redirectInterceptor");

note
最后一行表示将该拦截器登记到$httpProvider的拦截器中,同样应该写在公用服务的配置方法当中。

controller之间的通信问题

问题及场景
当有两个视图分别由两个controller控制时,其中一个视图发生变化,需通知另一个视图产生了此变化。

解决方案
总的来说,Angular中控制器通信有三种处理方法:

利用作用域继承的方式 即子控制器继承父控制器中的内容;

基于事件的方式 即$on,$emit,$boardcast这三种方法;

服务方式 写一个服务的单例然后通过注入来使用。

我选择了最后一种方法,示例代码如下:

    //JS
    var app = angular.module("myApp", []);
    app.factory("instance", function(){
        return {};
    });
    app.controller("MainCtrl", function($scope, instance) {
        $scope.change = function() {
        instance.name = $scope.test;
        };
    });
    app.controller("sideCtrl", function($scope, instance) {
        $scope.add = function() {
            $scope.name = instance.name;
        };
    });
    //html
    
click me
my name

note:
在Angular中服务是一个单例,所以在服务中生成一个对象,该对象就可以利用依赖注入的方式在所有的控制器中共享。
如果不是通过点击产生变化,还可结合$scope.$watch()方法来进行通信。
其他两种方法可参考站内文章:AngularJS控制器controller如何通信?

结语

以上为我在编写一个angular应用时遇到的问题及解决方案,记录并分享出来,欢迎大家指正!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78509.html

相关文章

  • angular - 收藏集 - 掘金

    摘要:如何在中使用动画前端掘金本文讲一下中动画应用的部分。与的快速入门指南推荐前端掘金是非常棒的框架,能够创建功能强大,动态功能的。自发布以来,已经广泛应用于开发中。 如何在 Angular 中使用动画 - 前端 - 掘金本文讲一下Angular中动画应用的部分。 首先,Angular本生不提供动画机制,需要在项目中加入Angular插件模块ngAnimate才能完成Angular的动画机制...

    AlexTuan 评论0 收藏0
  • MEAN.js 文档

    摘要:感谢使用框架本文档涵盖构建应用所需的基础知识。用于数据校验的组件及相关文件在此目录进行管理。除了自定义中间件外,还是用了诸多第三方的中间件,它们是五测试我们使用组件对服务端代码进行测试。识别当前导航从已有导航中删除给定标识的导航配置。 本文同步至个人博客 MEAN.js 文档,转载请注明出处。 Overview 感谢使用 MEAN.js 框架! 本文档涵盖构建 MEAN 应用所需的基础...

    Hydrogen 评论0 收藏0
  • 可能是你见过最完善微前端解决方案

    摘要:而从技术实现角度,微前端架构解决方案大概分为两类场景单实例即同一时刻,只有一个子应用被展示,子应用具备一个完整的应用生命周期。为了解决产品研发之间各种耦合的问题,大部分企业也都会有自己的解决方案。 原文链接:https://zhuanlan.zhihu.com/p/... Techniques, strategies and recipes for building a modern ...

    Kahn 评论0 收藏0
  • 前端练级攻略(第二部分)

    摘要:是文档的一种表示结构。这些任务大部分都是基于它。这个实践的重点是把你在前端练级攻略第部分中学到的一些东西和结合起来。一旦你进入框架部分,你将更好地理解并使用它们。到目前为止,你一直在使用进行操作。它是在前端系统像今天这样复杂之前编写的。 本文是 前端练级攻略 第二部分,第一部分请看下面: 前端练级攻略(第一部分) 在第二部分,我们将重点学习 JavaScript 作为一种独立的语言,如...

    BWrong 评论0 收藏0
  • 2017年前端流行数百个javascript库,你会几个?

    摘要:有数百个免费的库出来,为应用程序选择正确的框架变得非常困难。是流行的驱动技术之一,由于年创建。在这三个块中,有几个暴露低层接口的绑定。反应由,和许多开发人员和个人的社区维护。诞生于年,是一个轻量级的框架。 有数百个免费的JS库出来,为应用程序选择正确的JavaScript框架变得非常困难。一些开发商最终会抛弃,而其他开发者则迅速发展,并得到广泛采用。许多开发人员只知道像jQuery和R...

    CoXie 评论0 收藏0

发表评论

0条评论

cuieney

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<