<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Wayne&#39;s Blog</title>
    <description>工作近8年时间,目前在南太平洋小国新西兰工作生活,在一家不算小的小公司从事Java开发工作,不久前拿到新西兰的Resident Visa。
</description>
    <link>/</link>
    <atom:link href="/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Mon, 27 Jun 2016 03:50:31 +0000</pubDate>
    <lastBuildDate>Mon, 27 Jun 2016 03:50:31 +0000</lastBuildDate>
    <generator>Jekyll v3.1.6</generator>
    
      <item>
        <title>Angular -- 表单的验证</title>
        <description>&lt;p&gt;上篇介绍了ngModel的一些基本概念，以及如何使用NgModelController提供的API来完成小写变大写。本文将介绍另外一个重要的概念，那就是validation。Form的开发最为重要的就是向服务端POST数据，在POST之前，我们需要验证数据的正确性，这些验证可以是一些基础的验证，例如验证是否是全数字，也可以是调用API来验证，例如验证用户输入的用户名是否已经被占用了。要完成这些验证，就离不开另外几个属性。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;$validators&lt;/strong&gt; 保存一组validators的key-value集合，当model value被改变的时候调用。key作为validator的方法名，value是一个方法，其参数为modelValue和viewValue。
&lt;strong&gt;$asyncValidators&lt;/strong&gt; 异步验证，返回一个Promise对象，当成功时返回true，失败时返回false。所有的validators会并发执行，modelValue会在所有的validators都执行完成以后&lt;strong&gt;改变一次&lt;/strong&gt;。未完成的validators会存放在pending中。
&lt;strong&gt;$validate()&lt;/strong&gt; 执行所有的已注册的validators，执行顺序为同步-&amp;gt;异步。如果验证结果为无效，则model会被设置为undefined，除非&lt;code class=&quot;highlighter-rouge&quot;&gt;ngModelOptions.allowInvalid&lt;/code&gt;已经被设置为true。如果验证结果为有效，那么model会被设置为上次有效的modelValue。通常情况下，我们无须自己调用该方法。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;下面我们实现一个简单的validator去验证输入是否为数字。&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;form&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;test&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;numberOnly&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ng-model=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;model.value&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;hf-number-only&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
   
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;pre&gt;&lt;code class=&quot;language-JavaScript&quot;&gt;app.directive(&#39;hfNumberOnly&#39;, [&#39;$log&#39;, function($log) {
    return {
      priority: 1,
      require: &#39;ngModel&#39;,
      link: function(scope, ele, attrs, ctrl) {
        ctrl.$validators.numberOnly = function(modelValue, viewValue) {
          var regExp = /^^\-?\d+$/;
          if (!viewValue) return true;
          
          if (regExp.test(viewValue)) {
            return true;
          }
          
          return false;
        };
      }
    };
  }]);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;就这么简单，当每次在输入框输入时，validator就会自动被调用，当方法返回false时，label的html就变成了&lt;code class=&quot;highlighter-rouge&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;numberOnly&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;。&lt;/p&gt;

</description>
        <pubDate>Mon, 27 Jun 2016 00:00:00 +0000</pubDate>
        <link>/web/2016/06/27/Angular-form-validators.html</link>
        <guid isPermaLink="true">/web/2016/06/27/Angular-form-validators.html</guid>
        
        <category>Angular</category>
        
        <category>Directive</category>
        
        <category>Form</category>
        
        <category>ngModel</category>
        
        <category>validation</category>
        
        
        <category>Web</category>
        
      </item>
    
      <item>
        <title>Angular -- ngModel</title>
        <description>&lt;h1 id=&quot;ngmodel&quot;&gt;ngModel&lt;/h1&gt;
&lt;p&gt;在AngularJS中，当我们使用Form来创建表单的时候，使用最多的一个directive无疑就是&lt;strong&gt;ngModel&lt;/strong&gt;了。事实上AngularJS重写了很多基本的Form元素，例如form，input，input[text]等等，从而让我们可以很轻松的完成一些有趣的工作，或者很方便的对输入的元素进行验证。&lt;/p&gt;

&lt;p&gt;咱们不妨先看AngularJS对ngModel的描述：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The ngModel directive binds an input, select, textarea (or custom form control) to a property on the scope using &lt;strong&gt;NgModelController&lt;/strong&gt;, which is created and exposed by this directive.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ngModel指令首先会创建和暴露出来一个&lt;strong&gt;NgModelController&lt;/strong&gt;，使用NgModelController将input，select，textarea（或者自定义表单控件）绑定到scope上的一个属性。描述总是苍白的，我们不如看一下源码是如何定义的：&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ngModelDirective&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;$rootScope&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$rootScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;na&quot;&gt;restrict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;A&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;na&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;ngModel&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;^?form&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;^?ngModelOptions&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
		&lt;span class=&quot;na&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NgModelController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;na&quot;&gt;priority&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;na&quot;&gt;compile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ngModelCompile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;c1&quot;&gt;//preLink and postLink functions&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;由代码可以看到，ngModel首先是一个&lt;em&gt;A&lt;/em&gt;元素，其次它可以搭配的父元素有form和ngModelOptions，另外就是声明了NgModelController。但是ngModel都有哪些具体的职责呢？&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;ngModel&lt;/code&gt; is responsible for:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;Binding the view into the model, which other directives such as &lt;code class=&quot;highlighter-rouge&quot;&gt;input&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;textarea&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;select&lt;/code&gt; require.&lt;/li&gt;
    &lt;li&gt;Providing &lt;strong&gt;validation&lt;/strong&gt; behavior (i.e. required, number, email, url).&lt;/li&gt;
    &lt;li&gt;Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).&lt;/li&gt;
    &lt;li&gt;Setting related css classes on the element (&lt;code class=&quot;highlighter-rouge&quot;&gt;ng-valid&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;ng-invalid&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;ng-dirty&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;ng-pristine&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;ng-touched&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;ng-untouched&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;ng-empty&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;ng-not-empty&lt;/code&gt;) including animations.&lt;/li&gt;
    &lt;li&gt;Registering the control with its parent &lt;a href=&quot;https://docs.angularjs.org/api/ng/directive/form&quot;&gt;form&lt;/a&gt;.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;Note: &lt;code class=&quot;highlighter-rouge&quot;&gt;ngModel&lt;/code&gt; will try to bind to the property given by evaluating the expression on the current scope. If the property doesn’t already exist on this scope, it will be created implicitly and added to the scope.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;以上内容都是AngularJS定义好的，我们只需要知道怎么使用就可以了，比如使用一些常见的validation (maxlength, minlength, required)等等。除了这些基本的操作外，我们如何使用ngModel来做其它的事情？比如自定义validation，比如将输入小写字母转换成大写字母。这就要涉及到自定义directive，以及要用到强大的武器&lt;strong&gt;NgModelController&lt;/strong&gt;了。&lt;/p&gt;

&lt;h2 id=&quot;ngmodelcontroller&quot;&gt;NgModelController&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;NgModelController &lt;strong&gt;provides API&lt;/strong&gt; for the ngModel directive. The controller contains services for data-binding, &lt;strong&gt;validation&lt;/strong&gt;, CSS updates, and &lt;strong&gt;value formatting and parsing&lt;/strong&gt;. It purposefully does not contain any logic which deals with DOM rendering or listening to DOM events. Such DOM related logic should be provided by other directives which make use of NgModelController for data-binding to control elements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;NgModelController给ngModel提供了API。它包含的服务包含数据绑定，验证，CSS更新以及数据格式化和解析。它估计不包含任何与处理DOM展示和监听DOM事件的逻辑，此类逻辑应该由使用NgModelController其它directives来实现。所以我们需要使用NgModelController来实现我们想要的逻辑，例如大小写变换。&lt;/p&gt;

&lt;p&gt;在实现之前，我们先看NgModelController里的几个相关定义。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ul&gt;
    &lt;li&gt;$viewValue: 视图数据。从视图上获取到的真实value，对于&lt;code class=&quot;highlighter-rouge&quot;&gt;input&lt;/code&gt;元素来说，就是String。&lt;/li&gt;
    &lt;li&gt;$modelValue: 模型数据。控制器所绑定的model的值。&lt;/li&gt;
    &lt;li&gt;$parsers: 一个执行函数数组，它执行起来类似管道，上一个处理的结果会发送到数组的下一个函数当中。当视图数据变化的时候（例如在&lt;code class=&quot;highlighter-rouge&quot;&gt;input&lt;/code&gt;中输入了字母）执行。Parsers&lt;strong&gt;用于将视图数据解析到模型数据&lt;/strong&gt;。返回值为&lt;code class=&quot;highlighter-rouge&quot;&gt;undefined&lt;/code&gt;意味着解析错误，那么所有的validators都不会执行并且ngModel的值会被设置为&lt;code class=&quot;highlighter-rouge&quot;&gt;undefined&lt;/code&gt;，除非将&lt;code class=&quot;highlighter-rouge&quot;&gt;ngModelOptions.allowInvalid&lt;/code&gt;设置为&lt;code class=&quot;highlighter-rouge&quot;&gt;true&lt;/code&gt;。&lt;/li&gt;
    &lt;li&gt;$formatters: 和parsers类似，但是是按照函数插入的&lt;strong&gt;相反顺序&lt;/strong&gt;执行，最后一个返回结果最为最终的DOM值。&lt;strong&gt;用于将模型数据格式化到视图&lt;/strong&gt;。&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;我们要实现小写转大写的功能就需要使用到这几个属性。具体代码如下：&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ng-controller=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;FormCtrl as model&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;form&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;test&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;captalize&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;hf-captalize&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ng-model=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;model.value&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
	
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;button&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;button&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ng-click=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;model.value = &#39;change&#39;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;change&lt;span class=&quot;nt&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;pre&gt;&lt;code class=&quot;language-JavaScript&quot;&gt;var app = angular.module(&#39;app&#39;, []);

app.controller(&#39;FormCtrl&#39;, [&#39;$log&#39;, &#39;$scope&#39;, function($log, $scope) {
    var self = this;
    this.value = &#39;test&#39;;
    
    $scope.$watch(&#39;model.value&#39;, function() {
      $log.debug(&#39;Watched value: &#39; + self.value);
    });
  }]);
  
app.directive(&#39;hfCaptalize&#39;, [&#39;$log&#39;, function($log) {
    return {
      priority: 99,
      require: &#39;ngModel&#39;,
      link: function(scope, elem, attrs, ctrl) {
        function captalize(value) {
          $log.debug(&#39;captalize Called: &#39; + value);
          
          $log.debug(&#39;view value: &#39; + ctrl.$viewValue);
          $log.debug(&#39;model value: &#39; + ctrl.$modelValue);
          
          if (typeof value !== &#39;string&#39;) {
            return value;
          }
          
          var upper = value.toUpperCase();
          ctrl.$setViewValue(upper); // 将改变后的值赋给$viewValue
          ctrl.$render(); // 更新view
          return upper;
        }
        
        // 当在输入框中输入时，就会调用parsers里的方法，而当使用button改变模型数据的时候，并不触发parsers里的方法。
        ctrl.$parsers.push(captalize);
        // 当通过其它方式改变模型数据时，例如button被按下时，就会调用$formatters里的方法
        ctrl.$formatters.push(captalize);
//         captalize(scope.$eval(attrs.ngModel));
      }
    };
  }]);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;初始化运行结果如下图:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://7xvog5.com1.z0.glb.clouddn.com/angular-ng-model-captalize-init.png&quot; alt=&quot;angular-ng-model-captalize-init&quot; /&gt;&lt;/p&gt;

&lt;p&gt;第一个view value为何为NaN呢？这是因为，在我们初始化的时候，是通过代码将赋值给了model的，那么视图数据此时是没有值的。&lt;/p&gt;

&lt;p&gt;当我们点击change按钮了以后（下图），ng-click里面的表达式被调用，此时就会将模型值设置为’change’，然后依插入顺序调用parsers里的方法，所以view value是为改变之前的模型数据TEST，而模型数据此时已经改变了。
下图中的第二个view value为何是’CHANGE’，而model value是’change’呢？因为在captalize方法中，我们调用了&lt;code class=&quot;highlighter-rouge&quot;&gt;ctrl.$setViewValue()&lt;/code&gt;和&lt;code class=&quot;highlighter-rouge&quot;&gt;ctrl.$render()&lt;/code&gt;，此时将会改变视图数据，而模型数据还未改变。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://7xvog5.com1.z0.glb.clouddn.com/angular-ng-model-captalize-change.png&quot; alt=&quot;angular-ng-model-captalize-change&quot; /&gt;&lt;/p&gt;

&lt;p&gt;也可以尝试在输入框中自行输入一些字母来查看效果哦。我在jsbin里面已经创建了一个例子程序，可以&lt;a href=&quot;http://jsbin.com/faguha/123&quot;&gt;点击&lt;/a&gt;尝试。&lt;/p&gt;

</description>
        <pubDate>Fri, 24 Jun 2016 00:00:00 +0000</pubDate>
        <link>/web/2016/06/24/ngModel%E5%8F%8A%E8%87%AA%E5%AE%9A%E4%B9%89directives.html</link>
        <guid isPermaLink="true">/web/2016/06/24/ngModel%E5%8F%8A%E8%87%AA%E5%AE%9A%E4%B9%89directives.html</guid>
        
        <category>Angular</category>
        
        <category>Directive</category>
        
        <category>Form</category>
        
        <category>ngModel</category>
        
        
        <category>Web</category>
        
      </item>
    
      <item>
        <title>Angular -- Data Binding</title>
        <description>&lt;h1 id=&quot;data-binding&quot;&gt;Data Binding&lt;/h1&gt;

&lt;p&gt;Data-binding in Angular apps is the automatic synchronization of data between the model and view components. The way that Angular implements data-binding lets you treat the model as the single-source-of-truth (单一正确的数据源) in your application. The view is a projection of the model at all times (视图在任何时候都只是数据模型的投影). When the model changes, the view reflects the change, and vice versa.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;双向绑定，数据模型改变就会反映到页面上，而页面改变了数据，数据模型也会跟着变化。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;data-binding-in-classical-template-systems-&quot;&gt;Data Binding in Classical Template Systems （传统模板系统中的数据绑定）&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://docs.angularjs.org/img/One_Way_Data_Binding.png&quot; alt=&quot;&quot; /&gt;
Most templating systems bind data in only one direction: they &lt;em&gt;merge template and model components together into a view (我的理解：根据视图所需数据创建一个普通类作为模板，再通过数据模型来构造对象提供给视图)&lt;/em&gt;. After the merge occurs, changes to the model or related sections of the view are NOT automatically reflected in the view. Worse, any changes that the user makes to the view are not reflected in the model. This means that the developer has to write code that constantly syncs the view with the model and the model with the view.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;传统数据绑定的坏处显而易见，就是开发人员需要一直同步视图和数据模型。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;data-binding-in-angular-templates&quot;&gt;Data Binding in Angular Templates&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://docs.angularjs.org/img/Two_Way_Data_Binding.png&quot; alt=&quot;&quot; /&gt;
Angular templates work differently. First the template (which is the uncompiled HTML along with any additional markup or directives) is compiled on the browser. The compilation step produces a live view. Any changes to the view are immediately reflected in the model, and any changes in the model are propagated to the view. The model is the &lt;em&gt;single-source-of-truth （单一正确的数据源）&lt;/em&gt; for the application state, greatly simplifying the programming model for the developer. You can think of the view as simply an instant projection of your model.&lt;/p&gt;

&lt;p&gt;Because the view is just a projection of the model, the controller is completely separated from the view and unaware of it. This makes testing a snap because it is easy to test your controller in isolation without the view and the related DOM/browser dependency.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;双向绑定的好处&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;很大程度的简化了编程模型&lt;/li&gt;
    &lt;li&gt;controller同视图分开而不会意识到视图的存在，这样就会方便独立测试controller&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;🤔 不好的方面？
React采用了不同的方案，Flux强调单向数据流。Redux的做法是通过触发Action，由Reducer来改变数据，通过绑定数据到视图上来显示，视图上数据的改变不会影响数据模型，将改变后的数据通过Action传递到Reducer来进行改变。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;related-topics&quot;&gt;Related Topics&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.angularjs.org/guide/scope&quot;&gt;Angular Scopes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.angularjs.org/guide/templates&quot;&gt;Angular Templates&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Wed, 22 Jun 2016 00:00:00 +0000</pubDate>
        <link>/web/2016/06/22/Angular-Data-Binding.html</link>
        <guid isPermaLink="true">/web/2016/06/22/Angular-Data-Binding.html</guid>
        
        <category>Angular</category>
        
        <category>Data Binding</category>
        
        
        <category>Web</category>
        
      </item>
    
      <item>
        <title>我的移民故事——找工作篇</title>
        <description>&lt;p&gt;5月份，开始正式投简历，找工作，在著名的&lt;a href=&quot;www.seek.co.nz&quot;&gt;seek&lt;/a&gt;上投了十封简历之后，等待了两周，接到了两个猎头和一个大公司E的电话。&lt;/p&gt;

&lt;h3 id=&quot;e&quot;&gt;E公司笔试和电面&lt;/h3&gt;
&lt;p&gt;该公司比较注重SQL，这个是在后来才知道的。&lt;/p&gt;

&lt;p&gt;第一次笔试题，Java的，前端的，SQL的，Linux的，基本上都是一些问答题，有时间限制，答完以后下午收到第二次笔试题，一个完整的程序题，不过已经忘记是什么了。&lt;/p&gt;

&lt;p&gt;等待两天之后，接到电话，说笔试通过了，需要由公司的招聘部门先行电话面试。电面的难度其实很大，通话质量差的话你很难听清对方说的是什么，中文连蒙带猜可能还有戏，但是英文漏掉一个关键词，就完蛋。面试我的哥们恰好就属于口齿不清的那种，另外哥们估计在给我打电话的同时在和别人办事情，声音一会儿大一会儿小。电面到一半，我觉得应该没戏了。其间，他问了我一个问题就是SQL join，答得很烂，虽然脑子里面知道是什么，也知道怎么用，但是就是不知道如何去说，所以一定要多看原版书啊。&lt;/p&gt;

&lt;p&gt;好吧，该公司的面试草草收场。&lt;/p&gt;

&lt;h3 id=&quot;w&quot;&gt;W公司面试&lt;/h3&gt;
&lt;p&gt;W公司是由一家叫做Potentia的猎头公司推荐的，在去公司正式面试之前和猎头先进行了一次沟通。猎头其实不太懂技术，他们会根据公司的要求来筛选应聘者的简历，如果简历上的关键字匹配程度比较高的话，一般会约面谈，所以根据Job Description来修改简历很重要。猎头面试也比较简单，考察应聘者的口语能力是其中一项，另外还会问一些相关的问题，要自信，做过的技术多吹吹，不熟悉的也要吹成熟悉的，毕竟拿到一次真正的面试是我们的目的。&lt;/p&gt;

&lt;p&gt;在猎头的推荐之下，去了W公司，第一次面试我的是一个小组的Leader，介绍了一下公司的情况，然后就开始问了我一些基本概念问题，最后给了一套笔试题，做完笔试以后就回家等通知。下午回到家，猎头电话通知一面通过，约了一下二面的时间。&lt;/p&gt;

&lt;p&gt;二面面试官是个从业多年的大拿，面试的问题也都很简单，基本上是围绕简历在了解，最后就是现场写代码，刚开始由于理解错了面试官的问题，导致第一次做错，然后他重新确认了一下问题，马上写出了代码，并且一次通过，没有问题，结束面试。&lt;/p&gt;

&lt;p&gt;整个过程感觉没有什么问题，觉得应该会有希望，结果等了几周之后，猎头说还没有收到W公司的回复，应该是没有戏。。。&lt;/p&gt;

&lt;h3 id=&quot;p&quot;&gt;P公司面试&lt;/h3&gt;
&lt;p&gt;前面两家公司都是纽村大公司，而P公司就是一家小公司，只有10个人的规模。&lt;/p&gt;

&lt;p&gt;第一次面试的依然是Leader，照例都是介绍公司情况，并且简单了解技术能力和做一套笔试题，完了以后就回去等结果。Leader介绍的时候说应聘者有40多个，他们从中选择了6个进行笔试和面试，第一轮会淘汰掉3个，剩下三个会进行第二轮面试，很幸运我没有被淘汰。&lt;/p&gt;

&lt;p&gt;第二轮面试是群面，Boss，技术Leader，Senior Developer以及Tester一起面试，也基本上问了的都是围绕的简历，整个过程没有出现什么问题，由于当天是周五，所以会等待一个周末才会通知，临走的时候我还开玩笑的说：“It will be a tough weekend!”，他们还笑了。&lt;/p&gt;

&lt;p&gt;周一等到下午还没有电话，当时已经猜到是没戏了，不甘心，就打个电话过去问一问，也顺便想问一下他们的Feedback。如果公司拒绝了你，他们的Feedback其实挺重要的，他们也会比较诚实的告知你的情况。&lt;/p&gt;

&lt;h3 id=&quot;t&quot;&gt;T公司面试&lt;/h3&gt;
&lt;p&gt;T公司就是我前面说的贵人内推的，当时被推荐以后，我的信心就来了，觉得这次应该没有问题了。&lt;/p&gt;

&lt;p&gt;9月下旬一个周三下午，和COO聊了一会儿，聊开心了以后，COO给了我一份笔试题，都是Java基础，做完以后COO让我回去等通知。晚上收到邮件，联系了周五上午过去Final面。&lt;/p&gt;

&lt;p&gt;周五上午面试，面试我的哥们是现在关系很好的同事，他问了一些概念性问题，然后问一下相关的工作经历，都做了什么之类的。回去照例是等通知，又是一个周末，不过这次我的心态已经放平了，和室友们约着一起去Rutorua泡温泉玩去了😬&lt;/p&gt;

&lt;p&gt;周一回到奥克兰，晚上收到COO发的邮件，让我约个时间去签合同，就这样，尘埃落定！&lt;/p&gt;

&lt;h3 id=&quot;section&quot;&gt;总结&lt;/h3&gt;
&lt;p&gt;来这样一个国家找工作，面临很多困难。&lt;/p&gt;

&lt;p&gt;首先是语言，一定要练习好自己的口语和听力。&lt;/p&gt;

&lt;p&gt;其次是运气，一个萝卜一个坑，只有人走了公司才有可能招人，大部分公司都没有什么远大理想，保持住现在的规模对老板来说最为重要，所以多认识人，或许就会有公司有内推。&lt;/p&gt;

&lt;p&gt;再次就是技术能力，特别是相关概念的表达，来公司之后我也面试过几个人，有些连基本的HashMap都搞不清楚啊，这样的哪个公司敢用，《Java编程思想》&lt;strong&gt;英文版&lt;/strong&gt;还是要多看几遍再来吧。&lt;/p&gt;

&lt;p&gt;最后，心态放平，要相信自己总会找到的。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/rutorua-view.jpg&quot; alt=&quot;Rutorua-view&quot; /&gt;&lt;/p&gt;

</description>
        <pubDate>Sat, 18 Jun 2016 00:00:00 +0000</pubDate>
        <link>/%E7%A7%BB%E6%B0%91/2016/06/18/%E6%89%BE%E5%B7%A5%E4%BD%9C%E7%AF%87.html</link>
        <guid isPermaLink="true">/%E7%A7%BB%E6%B0%91/2016/06/18/%E6%89%BE%E5%B7%A5%E4%BD%9C%E7%AF%87.html</guid>
        
        <category>移民,</category>
        
        <category>面试</category>
        
        
        <category>移民</category>
        
      </item>
    
      <item>
        <title>我的移民故事——准备篇</title>
        <description>&lt;p&gt;这个故事还得从我媳妇那开始说。2011年，大学毕业第三个年头，国内大部分城市空气恶化刚刚通过数字全民普及开来的时候，和媳妇商量了一下，移民吧。。。&lt;/p&gt;

&lt;p&gt;移民何止口头上说说那么简单，面临的事情很多。况且那个时候，又是最懒的时候，英语不愿意去学，技术更不愿意花时间，每天回家还带着媳妇一起网游开黑，就这样蹉跎了近三年的时间。&lt;/p&gt;

&lt;p&gt;2013年9月份，媳妇顶不住丈母娘那边的压力，我们被逼婚了😄。结婚之后，突然责任感爆棚，去某著名二手货网站上买了三本新东方的词汇书，四级、六级和雅思，运气比较不错，买到的都是新的😂。从那个时候开始过起了三天打鱼两天晒网的生活，美其名曰，找状态。&lt;/p&gt;

&lt;p&gt;14年春节回到成都以后，在媳妇盛威之下，报了5月份的雅思，还是A类，当时多了个想法，万一抢不到WHV/SFV的话，还可以读一年书拿工签嘛。1750的报名费，为了不让其打水漂，三个月的时间，每天公交车上听英语，看英文网站，做雅思真题。考试如期而至，口语面对真人，非常紧张，好在遇到了好考官，最后的成绩比预想要好，总分6，WHV是够了。&lt;/p&gt;

&lt;h3 id=&quot;whv&quot;&gt;WHV&lt;/h3&gt;
&lt;p&gt;14年7月X号，虽然日子很重要，但已经记不住是几号了。就在这天，早上5点从床上爬起来，打开电脑登入移民局系统，开始人肉抢WHV，每年到了这个时候，都是几十万人一起抢1000个名额，可见竞争有多么激烈。最后凭借免费VPN，8点多钟抢到了名额！我知道，我的命运从此改变，不论后面的成败。&lt;/p&gt;

&lt;h3 id=&quot;section&quot;&gt;登陆前的准备&lt;/h3&gt;
&lt;p&gt;WHV签证下了以后，就开始做登陆前的准备了，分两部分准备。第一，面试相关，第二，移民材料。&lt;/p&gt;

&lt;p&gt;面试相关的准备工作，无非就是英语和技术，语言还是需要每天看听说，技术就是看和练。出来找工作，一定要&lt;strong&gt;多看原版书籍&lt;/strong&gt;，这样可以熟悉相关的技术词汇该如何用英语来表达，另外&lt;strong&gt;基础一定要扎实&lt;/strong&gt;，别问个Java的HashMap实现原理是什么，都不知道，那样别人怎敢要你。&lt;/p&gt;

&lt;p&gt;现在来纽村的移民越来越多，WHV/SFV过来拼的就是技术好工资低，如果没有过硬的实力，很难在这样的地方找到工作。英语是一切的基石，雅思听力在这个地方是远远不够的，这里有大量的移民，印度口、菲律宾、英国、印尼、大马、新加坡，当然还少不了KIWI，每一个都比美国口音难懂。口语只要能达到流利，不会在表达上让人理解不清就没有多大问题，所以建议练习一下如何表达。&lt;/p&gt;

&lt;p&gt;以上是总结，但实际上我在之前的几个月时间，一直在和我的小伙伴打麻将😂&lt;/p&gt;

&lt;h3 id=&quot;section-1&quot;&gt;找工作&lt;/h3&gt;
&lt;p&gt;找工作是个漫长的过程，语言、技术还有不可或缺的运气，如果真要按照重要性排名的话，我认为运气&amp;gt;语言&amp;gt;技术。&lt;/p&gt;

&lt;p&gt;15年3月6号，从上海出发，正式告别媳妇登陆纽村，运气很好找到一个洋人老头房东，开启了新西兰的崭新苦逼生活。
&lt;img src=&quot;/images/mt-roskill-view.jpg&quot; alt=&quot;Mt Roskill View&quot; /&gt;&lt;/p&gt;

&lt;p&gt;刚来的前一个半月都在熟悉环境，说白了就是到处浪，去认识小伙伴们，就在这个时候认识了一个贵人，也是因为他的推荐，我才有了现在的工作，这是后话。&lt;/p&gt;

&lt;p&gt;面试相关经历会单独写篇文章介绍，此处不说如此沉重的话题😂&lt;/p&gt;

&lt;h3 id=&quot;eoi&quot;&gt;EOI&lt;/h3&gt;

</description>
        <pubDate>Fri, 17 Jun 2016 00:00:00 +0000</pubDate>
        <link>/%E7%A7%BB%E6%B0%91/2016/06/17/%E5%87%86%E5%A4%87%E7%AF%87.html</link>
        <guid isPermaLink="true">/%E7%A7%BB%E6%B0%91/2016/06/17/%E5%87%86%E5%A4%87%E7%AF%87.html</guid>
        
        <category>移民,</category>
        
        <category>whv,</category>
        
        <category>雅思</category>
        
        
        <category>移民</category>
        
      </item>
    
  </channel>
</rss>
