AngularJS 小技巧

AngularJS 开发过程中用得到的日常小技巧。

默认提交为 JSON 的问题

这是一个 AngularJS 专用补丁,确保 POST 提交的不是 JSON 而是正常的 payload。

$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";

且 json 数据必须转换成 form 数据,详情请见 How can I post data as form data instead of a request payload?

(别的技巧待续,想听哪方面的技巧请留言)

AngularJS 父子 scope 之间的交流

本文是 《Parent/Child Controller Communication》 的译文。

======译文开始======

我最近经在教很多个朋友 AngularJS,而他们几乎都问了同样一个问题:

如何在 controller 之间传递消息(状态)?

这是个好问题。通常对初学者来说,它不直观。答案比我们想的要复杂(但实现起来很简单)。

有好多方法可以在 controller 之间通信 继续阅读AngularJS 父子 scope 之间的交流

angular.extend 实现解析

这是一篇废话,了解的请直接略过。

angular.extend 实现的代码如下:


/**

 * @ngdoc function

 * @name angular.extend

 * @module ng

 * @kind function

 *

 * @description

 * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
 * 将一个或多个 src 的 enumerable 属性复制到 dst 对象中。
 * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
 * 若您需要保留最初的 dst 对象,你可以
 * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
 * 传入一个空对象作为 dst 参数: `var object = angular.extend({}, object1, object2)` 。
 * Note: Keep in mind that `angular.extend` does not support recursive merge (deep copy).
 * 注:注意 `angular.extend` 不支持递归复制(deep copy)。
 *

 * @param {Object} dst Destination object.
 * @参数 {对象} dst 目标对象
 * @param {...Object} src Source object(s).
 * @参数 {一个或多个对象} src 源对象
 * @returns {Object} Reference to `dst`.
 * @返回 {对象} `dst` 目标对象的引用
 */

function extend(dst) {

  var h = dst.$$hashKey;



  for (var i = 1, ii = arguments.length; i < ii; i++) {

    var obj = arguments[i];

    if (obj) {

      var keys = Object.keys(obj);  //用 Object.keys 而不是 for in 遍历所有 enumerable 属性,浏览器原生支持到 IE9+

      for (var j = 0, jj = keys.length; j < jj; j++) {

        var key = keys[j];

        dst[key] = obj[key];   //将属性直接用等号赋值过来

      }

    }

  }



  setHashKey(dst, h);  //给该  Object 加上 hash 值,方便 angular 快速访问

  return dst;  //返回目标对象

}

拓展阅读

[翻译]简单实现 Angular-UI Bootstrap 的一个 alert service

导语

本文阐述 AngularJS 的 Bootstrap alert service 的简单实现方法,不依赖 jQuery,原文地址 https://coderwall.com/p/r_bvhg本文应该可以看作“一分钟入门 AngularJS Service 开发”,故转载并翻译之。

译文

Angular-UI Bootstrap 提供了不少流行的 Bootstrap 组件的 AngularJS directive(可显著降低代码量)。若您计划在您的 Angular App 中使用任何 Bootstrap 组件,强烈推荐您关注一下。它意味着直接包含 Bootstrap 的组件就能正确运行。 Service 用来在 controllers 之间共享代码。将代码从 controller 移出到 service,alert 是个正面的示例。 The Angular-UI Bootstrap 文档提供了如下例子:

VIEW

<div ng-controller="AlertDemoCtrl">
  <alert ng-repeat="alert in alerts" type="alert.type" close="closeAlert($index)">{{alert.msg}}</alert>
  <button class='btn' ng-click="addAlert()">Add Alert</button>
</div>

CONTROLLER

function AlertDemoCtrl($scope) {
  $scope.alerts = [
    { type: 'error', msg: 'Oh snap! Change a few things up and try submitting again.' }, 
    { type: 'success', msg: 'Well done! You successfully read this important alert message.' }
  ];

  $scope.addAlert = function() {
    $scope.alerts.push({msg: "Another alert!"});
  };

  $scope.closeAlert = function(index) {
    $scope.alerts.splice(index, 1);
  };
}

由于需要在 App 的不同 controller 里创建 alert,而代码在 controllers 之间互相引用又是个不良的编程习惯,所以我们得把它变成一个 service。

alertService

'use strict';

/* services.js */

// don't forget to declare this service module as a dependency in your main app constructor!
var appServices = angular.module('appApp.services', []);

appServices.factory('alertService', function($rootScope) {
    var alertService = {};

    // create an array of alerts available globally
    $rootScope.alerts = [];

    alertService.add = function(type, msg) {
      $rootScope.alerts.push({'type': type, 'msg': msg});
    };

    alertService.closeAlert = function(index) {
      $rootScope.alerts.splice(index, 1);
    };

    return alertService;
  });

View

这些标签也许会在您的 index.html 里,或者从一个头文件被包含过来。

<div>
  <alert ng-repeat="alert in alerts" type="alert.type" close="closeAlert($index)">{{ alert.msg }}</alert>
</div>

最后,我们需要将 alertService 的 closeAlert() 方法绑定到 $globalScope 里。

Controller

function RootCtrl($rootScope, $location, alertService) {
  $rootScope.changeView = function(view) {
    $location.path(view);
  }

  // root binding for alertService
  $rootScope.closeAlert = alertService.closeAlert; 
}
RootCtrl.$inject = ['$scope', '$location', 'alertService'];

我对这个绑定并不完全满意,希望能够直接从 html 标签直接调用这个 service 的 closeAlert 方法,但是还没发现怎么实现。 现在创建一个 alert 只需从任何一个 controller 调用 alertService.add() 即可。

function ArbitraryCtrl($scope, alertService) {
  alertService.add("warning", "This is a warning.");
  alertService.add("error", "This is an error!");
}

任何人有什么改进,请留言。希望此文是篇有用的 Angular.js service 介绍文。

译者:留言里真的有改进和实现方法,译者总结如下:

jwickers:以下代码无须注入到 controller 中就能运行。想从 html 标签中直接调用 closeAlert 方法只需增加一个 close 方法到 alert 对象中。

sur:我也添加了一个 clear 函数到 Alert Service 里面,这样只需调用 AppAlert.clear() 就能一键删掉所有的 alert。

译者:用 $sce 和 ng-bind-html 配合使用,可以使消息支持 html,须包含 AngularJS Router 文件。若不需要可以自行删掉调用了 $sce 的部分,一样可以正常运行。

alertService

.factory('AppAlert', [
      '$rootScope', '$timeout', '$sce', function($rootScope, $timeout, $sce) { 
        var alertService;
        $rootScope.alerts = [];
        return alertService = {
          add: function(type, msg, timeout) {
            $rootScope.alerts.push({
              type: type,
              msg: $sce.trustAsHtml(msg),
              close: function() {
                return alertService.closeAlert(this);
              }
            });

            if (timeout) { 
                $timeout(function(){ 
                    alertService.closeAlert(this); 
                }, timeout); 
            }
          },
          closeAlert: function(alert) {
            return this.closeAlertIdx($rootScope.alerts.indexOf(alert));
          },
          closeAlertIdx: function(index) {
            return $rootScope.alerts.splice(index, 1);
          },
          clear: function(){
            $rootScope.alerts = [];
          }
        };
      }
    ]);

View

<alert ng-repeat="alert in alerts" type="{{alert.type}}" close="alert.close()"><span ng-bind-html="alert.msg"></span></alert>

原文地址

Angular-UI Bootstrap alert service for Angular.js

拓展阅读

Angular.js: service vs provider vs factory?

[翻译]jQuery.isFunction() 和 (typeof variable === “function”) 的区别

通常测试一个 JS 对象是否是函数是这样:
(typeof fn === ‘function’)

然而,它并不总是有效 (IE8):

typeof alert => ‘object’
typeof document.createElement(‘input’).getAttribute => ‘object’

jQuery 1.4 之前也使用 typeof 的方法,但后来的版本修复了这个问题。所以想确定传递的对象确实是函数,使用 $.isFunction :

$.isFunction(function() {}) => true
$.isFunction(alert) => true
$.isFunction(document.createElement(‘input’).getAttribute) => true

附注

angularJS 的 angular.isFunction 用的是 typeof fn === ‘function’ 的方式。

参考

Why jQuery.isFunction?

扩展阅读

Type Checks – JavaScript Style Guide
What’s the difference between (typeof variable === “function”) and jQuery.isFunction()? – Stack Overflow