Angular for Vue Developers

There are now three clear leaders among the frameworks in the frontend: Angular, React, and Vue. I think we can judge the love of developers for the project by the number of stars on GitHub. At the time of this writing, Vue already has 161 thousand stars , React with 146 thousand is in second place , and Angular with its modest 59.6 thousand is in third place .


At first glance, it may seem that Angular is not as popular as other frameworks, but if we look at the results of statistics research from the Tecla portal, we will see that Angular occupies a rather large market share. For example, according to a study, Angular runs on more than 400 thousand sites, while Vue - on 100 thousand. I propose to sort this out. Consider why developers love Vue, why many applications are written in Angular, and what benefits a developer can get when using the framework from Google specifically for themselves.



About love


Most often, the following items are highlighted by Vue's special convenience (they are not listed in priority order):


  • Low entry threshold
  • Bundle size
  • Performance
  • Single File Components
  • Simple template syntax
  • Easy expansion with plugins and modules
  • DOM
  • Vue CLI

, — Developer Experience, . , . , , vue-cli, , , , .


Vue — , Angular ? — , , Vue. , API, . .



, . Angular , - / . .


SPA- API. ?


  • Vue: . fetch axios - ? ? ? ? — . — . , .
  • Angular: Angular HttpClient, , . , Angular CLI. Interceptor. , , .

, Angular , , , . , , 100% Vue.


, — , - ( ). , Angular .



, API. .



" " Vue . , , . ? ? , "" ? , Vuelidate. , .


Angular “ ” . FormGroup, , … . . , dirty . -.


Dependency Injection


DI — , . , Angular .


, , . , API . Angular , UserService. .


Vue:


  • , .
  • , , . , , .

Angular:


Angular , UserService. , , . , .


, DI. . , , . , .


CLI


CLI — , - . , . Vue CLI , , , . . Vue , CLI .


Angular CLI , , , , . , .


-. -. , , . .


Angular CLI , . , .



, -. Vue — , .


Angular , , . , .



TypeScript


TypeScript — , "JavaScript that scales", . JavaScript , , "" . JavaScript .


Angular TypeScript , JavaScript . TypeScript, . , , .


Vue TypeScript. , Vue CLI TypeScript . , . , , . . , TypeScript .


Router


SPA- Lazy Loading'. Webpack', , . .


Vue Vue Router. , , Vue. Vue Router , , .


Angular RouterModule, , ( , 16), . , .


Observable


Vue data . render() - . ?


— . — Observer, "". , , - . , "" . - .


Angular , . RxJS, . . , — , .



, Vue, Angular:


  • " "
  • Angular
  • CLI


Vue Angular.


Vue


. , , , — , .



<script>
export default {
  name: 'HelloHabr',
  props: {
    name: {
      type: String,
      required: true,
      validator: value => value.trim().length !== 0,
    },
  },
  data() {
    return {
      clickCount: 0,
      secondsCount: 0,
      intervalId: null,
    };
  },
  computed: {
    clicksPerSecond() {
      if (this.secondsCount === 0) {
        return 0;
      }

      const DECIMAL = 1000;
      const ratio = this.clickCount / this.secondsCount;

      return Math.round(ratio * DECIMAL) / DECIMAL;
    },
  },
  created() {
    this.intervalId = setInterval(() => {
      this.secondsCount++;
    }, 1000);
  },
  beforeDestroy() {
    clearInterval(this.intervalId);
  },
  methods: {
    countUp() {
      this.$emit('updateClick', ++this.clickCount);
    },
  },
};
</script>


<template>
  <div class="hello">
    <p>, !  {{ name }}.</p>

    <div class="click-place" :class="{ clicked: clickCount > 0 }">
      <button @click="countUp()"> !</button>
      <p v-if="clickCount > 0">  : {{ clickCount }}</p>
      <p v-else>     </p>
    </div>

    <div class="statistic">
      <p>    {{ secondsCount }} .</p>
      <p>  : {{ clicksPerSecond }}</p>
    </div>
  </div>
</template>

, , .



, :


<script>
  import HelloHabr from './components/HelloHabr.vue';

  export default {
    name: 'App',
    components: { HelloHabr }
    ...
  };
</script>

:


<template>
  <div id="app">
    <HelloHabr :name="name" @updateClick="updateClickCount" />
  </div>
</template>

Angular .


Angular



:


import {
  Component,
  EventEmitter,
  Input,
  OnDestroy,
  OnInit,
  Output,
} from '@angular/core';

@Component({
  selector: 'hello-habr',
  templateUrl: './hello-habr.component.html',
  styleUrls: ['./hello-habr.component.less'],
})
//         .
//     ,  "" ,
//       .
export class HelloHabrComponent implements OnInit, OnDestroy {
  //   
  @Input() name: string;

  //       
  @Output() updateClick = new EventEmitter<number>();

  //  
  clickCount = 0;
  secondsCount = 0;
  intervalId = null;

  //     
  ngOnInit() {
    this.intervalId = setInterval(() => {
      this.secondsCount++;
    }, 1000);
  }

  //     
  ngOnDestroy() {
    clearInterval(this.intervalId);
  }

  // ,    
  //      Vue,   
  //    
  get clicksPerSecond(): number {
    if (this.secondsCount === 0) {
      return 0;
    }

    const DECIMAL = 1000;
    const ratio = this.clickCount / this.secondsCount;

    return Math.round(ratio * DECIMAL) / DECIMAL;
  }

  //  
  countUp() {
    this.updateClick.emit(++this.clickCount);
  }
}


:


<p>, !  {{ name }}.</p>

<!--  Angular      -->
<div class="click-place" [class.clicked]="clickCount > 0">
  <!--     ,     -->
  <button (click)="countUp()"> !</button>

  <!-- ,   DOM-    -->
  <!-- else-      -->
  <p *ngIf="clickCount > 0; else elseBlock">
      : {{ clickCount }}
  </p>
  <!--  else-    -->
  <ng-template #elseBlock><p>     </p></ng-template>
</div>

<div class="statistic">
  <p>    {{ secondsCount }} .</p>
  <p>  : {{ clicksPerSecond }}</p>
</div>

, . Angular -. , . , . , , Vue.



Angular . , . , :


import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { HelloHabrComponent } from './hello-habr/hello-habr.component';

@NgModule({
  //   ,     
  declarations: [AppComponent, HelloHabrComponent],
  imports: [BrowserModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

, , . AppComponent.


. , . AppModule, . , . :


import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HelloHabrComponent } from './hello-habr.component';

@NgModule({
  //   ,     
  declarations: [HelloHabrComponent],
  // CommonModule     *ngIf
  imports: [CommonModule],
  //      HelloHabrModule
  exports: [HelloHabrComponent],
})
export class HelloHabrModule {}

, , , :


import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { HelloHabrModule } from './hello-habr/hello-habr.module';

@NgModule({
  declarations: [AppComponent],
  //      "HelloHabrComponent"
  imports: [BrowserModule, HelloHabrModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

. , Lazy-Loading'.


:


<hello-habr [name]="name" (updateClick)="updateClickCount($event)"></hello-habr>


, :


import { Component, EventEmitter, Input, Output } from '@angular/core';
import { BehaviorSubject, combineLatest, interval } from 'rxjs';
import { map, startWith } from 'rxjs/operators';

@Component({
  selector: 'hello-habr',
  templateUrl: './hello-habr.component.html',
  styleUrls: ['./hello-habr.component.less'],
})
export class HelloHabrComponent {
  @Input() name: string;
  @Output() updateClick = new EventEmitter<number>();

  clicksCount$ = new BehaviorSubject<number>(0);

  secondsCount$ = interval(1000).pipe(
    map(second => second++),
    startWith(0)
  );

  clicksPerSecond$ = combineLatest(this.clicksCount$, this.secondsCount$).pipe(
    map(([clicks, seconds]) => this.getClicksPerSecond(clicks, seconds))
  );

  countUp() {
    const newValue = this.clicksCount$.value + 1;

    this.updateClick.emit(newValue);
    this.clicksCount$.next(newValue);
  }

  private getClicksPerSecond(
    clicksCount: number,
    secondsCount: number
  ): number {
    if (secondsCount === 0) {
      return 0;
    }

    const DECIMAL = 1000;
    const ratio = clicksCount / secondsCount;

    return Math.round(ratio * DECIMAL) / DECIMAL;
  }
}

. :


  • . Angular.
  • .
  • . . . , . , .
  • , .


, . , , Angular:


  • .
  • : , , (interceptors), .
  • CLI, , , .
  • Dependency Injection — .
  • RxJS TypeScript .

:


  • .
  • .
  • Angular .

, , Vue. Angular 9 Ivy , , , . .


All Articles