前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >为什么AngularJs会火?

为什么AngularJs会火?

作者头像
javascript.shop
发布2019-09-04 15:51:13
8790
发布2019-09-04 15:51:13
举报
文章被收录于专栏:杰的记事本

Let’s see if we can discover why ?

Angular.js is a MV* (Model – View – Whatever) Javascript framework which is maintained by Google which excels in the creation of single-page-applications or even for adding some “magic” to our classic web applications.

I could spend all the day writing about why you should try Angular.js in your new project, but I feel that it would be better if we see it in action.

Data binding and scopes

The first question that usually comes to mind is: Does it support data binding?

Let’s see an example of Angular.js’ way of data binding:

{% raw %}“`html index.html Insert your name: 

Echo: {{user.name}}

代码语言:javascript
复制
</div>
In this little piece of code, there are a few things to explain but before that, I want you to get familiarized with the code:

## Try it

<body ng-app="app">
  <span>Insert your name:</span>
  <input type="text" ng-model="user.name" />
  <h3>Echo: {{user.name}}</h3>
</body>
***

**NOTE**: Don't worry too much about the `ng-app` thing at this moment.

As you see, what we write in the input, is echoed after it. But how? In plain words, we can make a two-way binding in the input thanks to the `ng-model` directive (more on directives later in the article).

Ok, but where are we saving that `user.name`? In our `$scope`. Every time we type something in our input, our `user.name` object in the scope is going to be updated. Then we can output our models thanks to Angular.js interpolation <span ng-non-bindable>`{{ ... }}`</span>. With this we can show the value of `user.name` in our HTML. With this, when we type a letter in the input, our `user.name` is saved into the scope and then we can see it in the HTML thanks to the interpolation.

Alright alright, that wasn't hard, but.... What is that `$scope` thing you're talking about? The `$scope` is basically the glue between our controllers and our templates. It is an object where we can put our models so we can achieve two-way data binding.

The idea is something like:
{% endraw %}

{% img /images/angularrocks/diag1.jpg %}

This means that we set `user.name` into our `$scope` from the template, so we can access it from our controller too.

Let's see a complex example:

{% raw %}

```javascript app.js
var app = angular.module('app', []);

app.controller('MainCtrl', function($scope) {
  $scope.message = 'World';
});

“`html index.html Hello, {{ message }} “`

See it

Hello, World


The first thing we are doing here is defining our Angular application. To do that we just create an Angular module which receives a name and an array of dependencies (Line 1).

With our app in place the next thing to do is to create our controller. We do this calling the controller method in our app module. We give it a name and a function.

The function receives the $scope (More on this later) that we are going to use for our two-way data binding.

Then we attach a string message in our $scope.

In our view you will notice that our body tags have things in it. What are those? They are directives, they teach new tricks to our HTML, and in this case, we are using two of them:

  • ng-app tells Angular that the body element contains our Angular application, that means that everything inside it will be treated by Angular. Normally you would use it in the htmltag. The parameter is the name of our app, so it matches the name we gave to it in the module.
  • ng-controller: with this directive, we assign as our element’s scope that controller. In this case MainCtrl.

Then we just interpolate our message in the template ?

This can be represented visually like so:

{% endraw %}

{% img /images/angularrocks/diag2.jpg %}

Because you’re so smart, I know you have a question: Can’t we bind functions to our $scope ?

Of course!

{% raw %}

“`javascript app.js var app = angular.module(‘app’, []);

app.controller(‘MainCtrl’, function($scope) { $scope.greet = function() { $scope.message = “Hello, ” + $scope.user.name; } });

代码语言:javascript
复制
<div ng-non-bindable>
```html index.html
<body ng-app="app" ng-controller="MainCtrl">
  What's your name?:
  <input type="text" ng-model="user.name" />
  <button ng-click="greet()">Click here!</button>
  <h3>{{ message }}</h3>
</body>

Try it

What’s your name?:  Click here!

{{ message }}

*** If we look into the controller, we can see how we attached to the `$scope` a function. That function will attach a message to the `$scope` as the result of a concatenation of a string and the content that was bound to our input `$scope.user.name` Then in the HTML we created a button and we used `ng-click` directive. In short this directive makes the element clickable so upon a click it will execute the function that we assigned to it `greet()`. **NOTE**: You will notice that pressing `enter` in the input doesn’t work. That is normal, I wanted to show how `ng-click` works ? {% endraw %} {% img /images/angularrocks/diag3.jpg %} ## Directives So what are these directives about? A directive is a way of teaching HTML new tricks. HTML is really powerful but sometimes we need more. And you think… Is that really needed? See yourself: “`html jquery_index.html“` What is this code doing? Prff I don’t have a clue, I see an id there, but who knows. Then we look in one of our 30 javascript files and we saw: “`javascript charts.js $(‘#chart’).pieChart({ … }); “` Aha! So it is the container of a pie chart. What’s the problem? You can’t figure out what your page does if you don’t look at every Javacript file that is attached to it. Then look at this code of an Angular app: “`html angular_index.html “` Isn’t this more clear? With a simple look we know that we are adding a pie chart, and not only that, we can see how big it is and what data it has assigned. As a curiosity, you can check a example `pie-chart` I did for fun [here](http://t.co/7vK8v2Om0N). ### Built-in directives Angular comes with a lot of built-in directives, let’s analyze some of them, but we already saw `ng-app`, `ng-controller`, `ng-click`, `ng-model` (You see the pattern here, `ng` is a diminutive of Angular). Imagine that we have a portion of our page that we want to show only if a certain property is true:“`html ShowI am only visible when show is true.“`

Try it

ShowI am only visible when show is true.


With ng-show we show the element (and children) only if the expression, in our case the value of the binding, is true.

Note how we used ng-click this time. There is no need to create a function in our controller (we don’t even have a controller this time!), we can write an expression as the directive’s argument and in this case, we toggle the value of show. Which starts undefined and is set to true with the first click.

We also have ng-hide which does the opposite ?

Let’s go to something funnier. What if we have an array of objects and we want to list it?

“`javascript app.js var app = angular.module(‘app’, []);

app.controller(‘MainCtrl’, function($scope) { $scope.developers = [ { name: “Jesus”, country: “Spain” }, { name: “Dave”, country: “Canada” }, { name: “Wesley”, country: “USA” }, { name: “Krzysztof”, country: “Poland” } ]; });

代码语言:javascript
复制
{% raw %}
<div ng-non-bindable>
```html index.html
<body ng-app="app" ng-controller="MainCtrl">
 <ul>
   <li ng-repeat="person in developers">
     {{person.name}} from {{person.country}}
   </li>
 </ul>
</body>

{% endraw %}

See it

from


NOTE: In the See it I had to modify the code because it is really tricky to add interactivity to the articles.

Well, we define a list of objects in our controller, nothing that would surprise you and then we use the ng-repeat directive in our HTML.

How does it work?

ng-repeat will create a new template for every item in the collection. So in our case and since we have 4 items in it, it will create this piece of code four times:

{% raw %}

代码语言:javascript
复制
<li ng-repeat="person in developers">
 {{person.name}} from {{person.country}}
</li>

{% endraw %}

Every copy will contain its own scope. So now in this template we don’t have the controller as the scope, in this case, the person is the scope. This means that we don’t have access to our parent controller from here (This isn’t totally true, there are ways to access it).

Let me show it visually:

{% img /images/angularrocks/diag4.jpg %}

Much better ?

Can we create our own directives?

What do you expect? Of course we can!

We can create almost anything. Directives for modal dialogs, accordions, paginators, charts, search form…

Are they always that visual? No, you can create directives that won’t do anything visual.

Let’s begin with an example.

Going back to our greet example, we had this: {% raw %}“`html form.html What’s your name?:  Click here!

{{ message }}

代码语言:javascript
复制
</div>

It works great but what if we want the input to have the focus when the page loads? jQuery right? We grab the input and we call the `focus()` method in it. **NO**.

With directives we want our HTML to be as self-descriptive as possible so we are going to create a `focus` directive.

```javascript focus.js
app.directive('focus', function() {
  return {
    link: function(scope, element, attrs) {
      element[0].focus();
    }
  };
});

So we are calling the directive function of our app object, this like our controller receives the name of the directive and a function.

Directives are the most complex thing in the entire Angular.js and for the sake of simplicity (this is like a showcase article :P) I won’t give excessive details (but I promise several articles on the subject in a future).

A directive needs to return an object and there we can define some attributes in it, in our case, none. A directive can also return a link function. It is in the link function where we put most of our template logic.

We can register DOM listeners here, update our DOM, etc.

The link function receives 3 parameters (Actually 4, but that is more advanced), the scope, the element itself and its attributes attr.

Here we can bind our element to click event or mouseenter among others.

In our case we grab the first element (our input) and call the focus function in it.

If you’re wondering how can we work with the element, check the official doc: Element API

Simple as that. The only thing needed now is to use it. Just put the directive name in the element you want to grab your focus:“`html form.html What’s your name?:  Click here!

{{ message }}

“`

NOTE: There is no Try it this time, it seems like Octopress is grabbing the focus too and my example won’t work here.

Fair enough, this directive was really simple.

What about a directive that will render some HTML?

Here it is:

“`javascript hello.js app.directive(‘hello’, function() { return { restrict: “E”, replace: true, template: “Hello readers, thank you for coming“ } });

代码语言:javascript
复制
This one returns the object and in there we set some attributes (as we said earlier).

* restrict: A directive can be placed in several places:
  * **A**ttribute, like: `<div foo></div>`
  * **E**lement, like: `<foo></foo>`
  * **C**lass, like: `<div class="foo"></div>`
  * Co**M**ment, like: `<!-- directive: foo -->`
* replace: If we set this to true, our element will be replaced with our new template
* template: Here we put the template we want to append (or replace as we have seen) into the element.

We are restricting our directive to element (is restricted to attribute by default) and we are specifying a template to replace our element.

There are a lot more options that we can use in our directives, but these will do the work we need.

Note that we are not using a link function here, that is because we need no logic here.

How to use it? Easy:

<div ng-non-bindable>
```html index.html
<hello></hello>

See it

Hello readers, thank you for coming


And if you inspect the code, you will see that the <hello></hello> as been replaced for <div>Hello readers, thank you for coming</div> as we expected.

Filters

Imagine that we have a view where we show a shopping basket:“`html There are 13 phones in the basket. Total: {{ 1232.12 }} “`

See it

There are 13 phones in the basket. Total: 1232.12


Notice how we can use some basic expressions in the interpolation. In this case we are printing a number. We can read it and realize that we are talking about $1,232.12 but wouldn’t it be better if we can convert that number into money?

Of course, and that is really easy with filters. There is an example of the currency filter:“`html There are 13 phones in the basket. Total: {{ 1232.12 | currency }} “`

See it

There are 13 phones in the basket. Total: $1,232.12


Much better, isn’t it?

As you can see, we can use a filter using the | character. It is like we do in a Unix environment, piping.

We can pipe one or more filters in a expression.

For example, we can specify an order in a ng-repeat. Let’s try it out with the developers collection we made earlier:“`html

  • {{ person.name }} from {{ person.country }}

“`

See it

from


We can see here something interesting. We can pass parameters to the filters.

The orderBy filters receive a predicate which it will use to order. In our case we passed name so we will order the list by name. Note that if we put -name as the predicate, we will order it in reverse mode ?

So you are thinking at this moment… Not bad, they can be useful…

Ok, this next one will blow your mind.

Imagine that we don’t have 4 developers, we have 300 and we want to filter them (by name, country…). So you start planning how to filter your collections, swap the non-filtered one with the filtered…

It is a more simple way (Again using the same controller as before with the list of developers):“`html Search: 

  • {{ person.name }} from {{ person.country }}

“`

Try it

Search: from


Wow! That is awesome. We only needed a filter!

With the filter filter, you only need to pass a parameter which will contain the filter itself. In this case, we pass searchwhich is bound to our scope and it is populated by our input.

If you want, you can make the filter more precise by doing something like this:“`html Search: 

  • {{ person.name }} from {{ person.country }}

“`

With this (notice how we are binding to search.name in the input) we are now filtering just by name. The filter parameter doesn’t change. It is bound to the search object and it will find there a name populated with our input and then filtered by name.

I hope you’re excited with this too ?

What about creating our own filter? Yeah!

A filter to capitalize the text. How? Like this:

“`javascript capitalize.js app.filter(‘capitalize’, function() { return function(input, param) { return input.substring(0,1).toUpperCase()+input.substring(1); } });

代码语言:javascript
复制
A filter returns a function which receives the input (the result of the interpolation) and the filter parameter. The function returns our new input. In this case it capitalizes the input.

Then, we just need to use it:

<div ng-non-bindable>
```html
<span>{{ "this is some text" | capitalize }}</span>

See it

This is some text


We had to wrap our string into quotes to make it a literal string. Then we “pipe” our capitalize filter and it works!

Services

And our last section for this article, services. What is a service? They are singleton classes that provide certain functionality to our app.

Instead of splitting our app logic into the controllers, we can put that logic into different services.

Angular has a lot of built-in services, managing $http requests, $q for promises, etc. But in this part we are not going to talk about any built-in service, because they are more difficult to explain and that belongs to a new article. Instead we are going to create a simple one.

One of the more common uses for a service is to share information among controllers. Every controller has its own scope so you can’t bind to other controller scope. The solution is to use services, so you can have the data in one central place and then use it where you want.

First, let’s try this without the service to see the problem:“`html index.htmlMainCtrl: SecondCtrl: “`

“`javascript controllers.js app.controller(‘MainCtrl’, function($scope) {

});

app.controller(‘SecondCtrl’, function($scope) {

});

代码语言:javascript
复制
## Try it

<div ng-controller="MainCtrl">
  MainCtrl:
  <input type="text" ng-model="user.namey">
</div>
<div ng-controller="SecondCtrl">
  SecondCtrl:
  <input type="text" ng-model="user.namez">
</div>

***
{% endraw %}

Well, since you have your inputs bound to the same model, you expect that writing in a box, will update the other one. Like this:

{% img /images/angularrocks/diag5.jpg %}

That is not true, what is really happening is this:

{% img /images/angularrocks/diag6.jpg %}

So we are going to fix this with a service which will hold the user name so we can use it in both controllers:

```javascript user_information.js
app.factory('UserInformation', function() {
  var user = {
    name: "Angular.js"
  };
  
  return user;
});

We used the factory function of our app module to create a service. There are other advanced ways to create services (using the service and provider functions, but that belongs to another post).

There are several ways to create a service, and in this case, we are creating a private user object with a predefined name and then we are returning it.

Good, how can I use this in our controllers? Like this:

“`javascript controllers.js app.controller(‘MainCtrl’, function($scope, UserInformation) { $scope.user = UserInformation; });

app.controller(‘SecondCtrl’, function($scope, UserInformation) { $scope.user = UserInformation; }); “`

With this we get something like:

{% img /images/angularrocks/diag7.jpg %}

Try it

MainCtrl: SecondCtrl: 


Well this seems to work.

Now our $scope.user in both MainCtrl and SecondCtrl is using UserInformation and since the service is a singleton, if we update it from one controller, the other will be updated too. So your question now is: Where does the UserInformationparameter come from?

Angular uses dependency injection to inject the services where we need them. Explaining how the dependency injectionworks is not a subject for this article. But in plain words, when we create a service, we can inject it in any controller, directive or even in another service. How? Just passing as a parameter the name of the service.

You’re maybe wondering if this is the same for $scope. Well, $scope is maybe one of the exceptions that is not really a service that is injected into our controllers.

Conclusions

With this we end the first (but not the last :)) article of this blog.

Angular.js is a great framework and I think that you are already in love with it. I expect to see you here for the next articles!

I hope you enjoyed it and I expect your comments ?

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2014年12月26日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Data binding and scopes
    • Echo: {{user.name}}
    • See it
    • Try it
      • {{ message }}
      • Try it
      • See it
        • Can we create our own directives?
          • {{ message }}
            • {{ message }}
            • See it
            • Filters
            • See it
            • See it
            • See it
            • Try it
            • See it
            • Services
            • Try it
            • Conclusions
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档