angularjs和WebApp(试着翻译)

2.0跟IE的关系

IE6和IE7无法特别稳定执行,因为custom tags 和 hashchange events无法使用

在IE8里面则需要手动定义自定义标签,并插入到DOM树上,比如(document.createElement(‘ng-pluralize’),document.createElement(‘ng-view’)

3.0数据绑定和作用域切换

事件绑定机制根据事件自动触发,触发之后进行数据检查,$scope本身提供了一个key/value存储的哈希表。输入事件(比如键盘被按键了,鼠标焦点之类)、浏览器事件(timeout一类)、服务唤起(比如$http一类的)都会导致脏数据检测。顺便有些情况下,比如地址栏被改变了,或者你希望直接改变那里面的数据,就得手动调用 $scope.$apply()。一般情况下不推荐这么做。

4.0 $rootScope对象之妙用

每个controller里面的scope都是rootscope的子类,然后跟rootscope其实有联系。

$scope extends $rootScope

看个例子

App.run([‘$rootScope’,function($rootScope) { //this will be available to all scope variables $rootScope.includeLibraries = true; //this method will be available to all scope variables as well $rootScope.include = function(libraries) { var scope = this; //attach each of the libraries directly to the scope variable for(var i=0;i<libraries.length;i++) { var key = libraries[i]; scope[key] = getLibrary(key); } return scope; }; }]);

controller实例里面可以解决的方式如下

App.controller(‘SomeCtrl’, [‘$scope’, function($scope) { if($scope.includeLibraries) { //the flag was set in the $rootScope object $scope = $scope.include([‘plugin1’, ‘library1’]); } }]);

5.$apply 和 $digest 和 $$phase

如果在angularjs中引入了第三方类库,你需要有个额外的功能监视数据的变化,比如第三方框架使用了某些动作改变页面数据,这时候需要调用 $scope.$apply(),这个动作意味着调用了$watch把所有的变量变化都监控了一下,本来这件事是系统后台调用的。

部分情况下这个动作可能会抛出异常,因为后台此时正在运行一个digest,为了避免这种情况的发生,需要使用一个全局对象 $scope.$$phase来判断当前是否有后台进行的数据更新操作。

于是为了稳妥起见我们可以自己使用 下面的安全更新操作

//when you add it to the $rootScope variable, then it’s accessible to all other $scope variables. $rootScope.$safeApply = function($scope, fn) { fn = fn || function() {}; if($scope.$$phase) { //don’t worry, the value gets set and AngularJS picks up on it… fn(); } else { //this will fire to tell angularjs to notice that a change has happened //if it is outside of it’s own behaviour… $scope.$apply(fn); } }; //and you can run it like so. $scope.some_value = ‘value…’; $scope.$safeApply($scope, function() { //this function is run once the apply process is running or has just finished });

下面有个例子,这里我们要修改location url所以使用下面的代码

//be sure to inject $scope and $location somewhere before this var changeLocation = function(url, force) { //this will mark the URL change $location.path(url); //use $location.path(url).replace() if you want to replace the location instead $scope = $scope || angular.element(document).scope(); if(force || !$scope.$$phase) { //this will kickstart angular if to notice the change $scope.$apply(); } };

6.0在services和controller中进行通信

如果现在有个用户动作需要影响几乎所有的controller和directive的话,那就需要使用$emit, $on and $broadcast

如果你现在有个需要所有controller都处理的事件,可以用broadcast来做

//get the topmost scope var $scope = angular.element(document).scope(); //logout event var logoutEvent = ‘logout’; var logoutArgs = [‘arg’]; $scope.$broadcast(logoutEvent, logoutArgs); //login event var logoutEvent = ‘logout’; var logoutArgs = [‘arg’]; $scope.$broadcast(logoutEvent, logoutArgs);

接下来在每个controller里面接收代码如下

// //in your controller

//

App.controller(‘Ctrl’, [‘$scope’, function($scope)

{ $scope.$on(‘logout’, function(args) { alert(‘bye bye’); });

$scope.$on(‘login’, function(args) { alert(‘hello there’); }); }]);

在directive里面

// //in your directive // App.directive(‘sessionStatus’, function() { return function($scope, element, attrs) { $scope.$on(‘login’, function() { element(‘html’, ‘You are logged in!’); }); $scope.$on(‘logout’, function() { element(‘html’, ‘You are logged out!’); }); }; });

如果在是字controller里面提交一个动作给全局,那么可以用$emit

App.controller(‘Ctrl’, [‘$scope’, function($scope) { $scope.onLogoutClick = function() { $scope.$emit(‘logout’); } }]); //upper $scopes will respond to this with the same $on method.

7.0 为router上的controller加上点附加处理功能

example of it:

//checkout the route code below first before reading this
App.controller('Ctrl', ['$scope', '$http', 'argument1', 'argument2', 'argument3',
                function($scope,   $http,   argument1,   argument2,   argument3) {
  alert(argument1); //someDependeny's value or toString method
  alert(argument2); //"some value"
  alert(argument3); //the response.data value returned from GET /path/to/some/url
}]);

//here's where the magic happens
App.config(['$routeProvider',function($routeProvider) {
  $routeProvider.when('/some/page/with/an/:id',{
    templateUrl: '/path/to/some/template.html',
    controller: Ctrl,
    resolve: {
      // this is a registered dependency and works the same
      // as a dependeny injection would within a controller
      argument1: 'someDependency', 

      //this is resolved instantly since there is nothing going on
      argument2: function() { return 'some value'; }, 

      argument3: function() {
        return $http.get('/path/to/some/url',function(response) {
          //this is what is returned as the value for argument3
          return response.data; 
        }
      }
    }
  });
}]);

When the application makes it’s way to the path /some/page/with/an/:id

这个动作实际上就是绕过router的动作,直接处理请求并发起请求绕过了。这算是一种补充数据的办法

当然,还可以直接改router对象

The $route variable can also be injected directly into the controller and this can be used to fetch information about the current route:

App.controller('Ctrl', ['$route', function($route) {
  $route.current.templateUrl; //the URL of the template
  $route.current.params; //same as $routeParams
  $route.current.controller; //the name of the controller (Ctrl)
}]);

继续

8.0自定义自己的services

your application.

App.factory('myHttp',['$http',function($http) {
  return function() {
    get : function(url, success, fail) {
      $http.get(url).success(function(response) {
        return response.data;
      }).error(fail);
    }
  };
}]);

//this service can now be called by doing...
$myHttp.get('/path', function(data) {
  alert(data);
});

Also, below is a description of how data is shared between services within the same model.

App.factory('myFoo',['$http',function($http) {
  //any variables defined in this area will be ACCESSIBLE
  //within the any of the other services which are defined
  //within the same module. So if a variable called foo...
  var foo = 'bar';
  //then foo can be accessed in another service. Be sure to
  //keep this in mind since it's hard to debug
  return foo;
}]);

App.factory('myBar',['$http',function($http) {
  var bar = 'bar2';
  return foo.toString() + bar; //this should return either bar2 or barbar2
}]);

You can also inject any of your own services into any other services when created; this is very useful for code reuse and testing.

这地方就是自己弄个一个services,封装了原来的http动作,然后加上了点自己的动作。

9.0 ngshow什么的改变css

The same effect can be created by using angular

<div class="session">
  <span class="admin" data-ng-show="isAdmin">Hello Adminspan>
  <span class="admin" data-ng-hide="isAdmin">Hello Userspan>
div>

Just be sure to set the binding value

$scope.isAdmin = true; //or false or whatever

This works, but when the page is still downloading (when first loaded) you may see both values at the same time so to get around this just use cloaking.

<div class="session ng-cloak">...div>

And define the CSS for it as well:

.ng-cloak {
  /* this will change to block when scope and angular is ready */
  display:none;
}

Oh! And one more thing. If you wish to set the isAdmin value directly into your HTML, then do the following using the data-ng-init:

<div class="session ng-cloak" data-ng-init="isAdmin=false;">
  <span class="admin" data-ng-show="isAdmin">Hello Adminspan>
  <span class="admin" data-ng-hide="isAdmin">Hello Userspan>
div>

The data-ng-init attribute is useful for pre-setting values

10.错误异常捕获

route is not recognized within your application.

$routeProvider.when('/404',{
  controller : ErrorCtrl
});
$routeProvider.otherwise({
  redirectTo : '/404'
});

then you can capture the event within your scope by doing the following:

App.run(['$rootScope','$location',function($rootScope, $location) {
  $rootScope.$on("$routeChangeError", function (event, current, previous, rejection) {
    //change this code to handle the error somehow
    $location.path('/404').replace();
  });
}]);

set a custom service to wrap all your AJAX calls then you can catch errors before they’re passed onto other parts of your application.

App.factory('myHttp',['$http','$location',function($http, $location) {
  var onEmpty = function() {
    window.location = '/404';
  };

  return function() {
    get : function(url, success, fail) {
      $http.get(url).success(function(response) {
        var data = response.data;
        if(!data) {
          onEmpty();
          return;
        }
        success();
      }).error(onEmpty);
    }
  };
}]);

Be sure to only use this method when you access resources and data that is required within your application (like JSON data for a specific view).

11 使用$index在循环中获取循环变量进度

To get access to the index of a loop in angular you can access it from the $index value directly.

<ol>
  <li data-ng-repeat="option in options">
    <h2>Option #{{ $index + 1 }}: {{ option.value }}h2>
  li>
ol>

Keep in mind that there are also other options available such as $first, $middle, and $last. All of these and more are covered within the

location对象的获取

angular可以处理location对象,专门用于保存本地链接地址的哈希值

To keep track of the URL when it changes, you will need to setup a polling event.

App.run(['$rootScope', '$location', function($rootScope, $location) {
  $rootScope.$watch(
    function() { return $location.path() },
    function(path) {
      //new path!
      alert(path);
    }
  );
}]);

Additionally you can set these events explicitly within your scope variable

App.run(['$rootScope', function($rootScope) {
  $rootScope.$on('$locationChangeStart', function(event, newUrl) {
    alert('new location');
  });
}]);

自定义filter

App.filter(‘my’, function() {
return function(data) {
return data;
};
});
You can use of these filters directly in your HTML:

<span class=”some-data”>{{ value | my }}<span>
Or you can also access these filters directly in your services and controllers via dependency injection.

App.factory(‘someService’, [‘$filter’, function($filter) {
return function(data) {
return $filter(‘my’)(data);
};
}]);

表单的处理

<form novalidate class=”simple-form”>
<ol class=”fields”>
<li>
<label for=”input-name”>Name:</label>
<input id=”input-name” type=”text” data-ng-model=”name” />
</li>
<li>
<label for=”input-email”>Email:</label>
<input id=”input-email” type=”email” data-ng-model=”email” />
</li>
</ol>
<button data-ng-click=”submit()”>Submit</button>
</form>

表单出来的时候是处理的双向绑定数据,数据提交需要自己处理

这是国家化代码的例子

Ideally you wouldn’t stick the english translations directly into your own webapge so you can switch this so that translations are looked up in a global translation lookup table.

You would have to define your own lookup since this is something angular doesn’t provide by itself.

var LOOKUP = {
‘messages.zero’ : ‘No have no messages in your inbox’,
‘messages.one’ : ‘You have one message in your inbox’,
‘messages.many’ : ‘You have %messagesCount% messages in your inbox’
}
var translate = function(key, args) {
var data = LOOKUP[key];
if(data) {
for(var key in args) {
var value = args[key];
key = ‘%’ + key + ‘%’;
data = data.replace(key,value);
}
return data;
}
return ”;
};

时间日期国际化的例子

<!– this shows up as Sep 9, 2012 –>
<span class=”string-date”>{{ site.curl_left }} ‘2012-09-01′ | date:’medium’ {{ site.curl_right }}</span>

<!– same thing but longer and using a variable –>
<span class=”string-date”>{{ site.curl_left }} someDateVariable | date:’fullDate’ {{ site.curl_right }}</span>

<!– and you can set your own –>
<span class=”string-date”>{{ site.curl_left }} anotherDateVariable | date:’EEEE, MMMM d,y’ {{ site.curl_right }}</span>
You can also access the date filter directly within your controllers and services with use of the $filter service.

var dateFilter = $filter(‘date’);
var mediumDateString = dateFilter(‘2012-09-01’, ‘medium’);
var fullDateString = dateFilter(someDateVariable, ‘fullDate’);
var anotherDateString = dateFilter(anotherDateVariable, ‘EEEE, MMMM d,y’);

 

 

Advertisements

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s