WEB start

Компьютеры. Интернет. Заочное профессиональное обучение. 055-966-10-17

hit 
counter

Обучение

Широкий спектр программ и различных форм обучения

Возможность заочного, дистанционного обучения 055-966-10-17
  • Программирование. Современные языки и технологии.
  • Обслуживание персональных компьютеров.
  • Компьютерные сети. Защита информации.
  • Интернет. Планирование, создание WEB-сайтов. Дизайн, программирование. CEO, продвижение сайтов в интернет.
  • Основы современных IT - технологий.

Наши преимущества

  • Наши программы обучения ориентированы на конкретного слушателя. Вы можете обучаться по одной из предложенных Вам программ, а можете самостоятельно составить, откорректировать, откорректировать свою персональную программу обучения. Преподаватель, консультант помогают Вам сориентироваться в материале курса при выборе программы обучения.
  • Обучение индивидуальное. Преподаватель проводит занятие только для Вас, ориентируясь на Ваши возможности, предыдущие знания и опыт, скорость восприятия нового материала.
  • Вы учитесь в удобное для Вас время, в удобной для Вас форме, может быть выбран гибкий график занятий, в соответствии с Вашими возможностями и пожеланиями.
  • Обучение проводится дистанционно. Вы можете обучаться, сидя за Вашим компьютером дома или на работе, не тратя время на поездки к месту обучения.


Регистрация на сайте

typescript

  • Обмен данными между родительским и дочерним компонентом (Angular component interaction)

    @input


    @output


    Decorators


    Event emitter


    C помощью декораторов @Input, @Output и API EventEmitter можно обеспечить обмен данными между родительскими и дочерними компонентами.


    Декоратор @Input

    Дочерний компонент с помощью декоратора input может получать данные от родительского, а  с помощью декоратора output - посылать.


    Для получения данных от родительского компонента дочерним:

    - в дочернем компоненте создаём свойство, в которое данные будем получать, декорируем его с помощью декоратора @Input

    - в родительском компоненте создаём public - свойство, которое будем передавать

    - при вызове дочернего компонента через созданное нами свойство привязываем к свойству дочернего компонента данные из родительского.


    Родительский компонент:

    import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'app'; public string1 = <string> 'Data from parent...'; }


    Шаблон родительского компонента - вызов дочернего:

    <h1>This is parent component:</h1> <hr> <app-inoutcomponent [inFromParent]='string1'></app-inoutcomponent>


    Дочерний компонент

    import { Component, OnInit, Input } from '@angular/core'; @Component({ selector: 'app-inoutcomponent', templateUrl: './inoutcomponent.component.html', styleUrls: ['./inoutcomponent.component.css'] }) export class InoutcomponentComponent implements OnInit { @Input() public inFromParent: string; constructor() { } ngOnInit() { } }


    Шаблон дочернего компонента 

    <h1>This is child component:</h1> <h3>{{inFromParent}}</h3>


    Результат



    Добавим в родительский компонент метод, который меняет это свойство. Привяжем его к событию click кнопки.

    import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'app'; public string1 = <string> 'Data from parent...'; changeChildData() { this.string1 += ' Changed '; } }


    При каждом нажатии к строке будем приписывать текст: this.string1 += ' Changed ';


    Результат после 2-х кликов:



    Декоратор @Output и  EventEmitter 

    Передача данных от дочернего компонента к родительскому.

    Для этого используем декоратор @Output и привяжем к дочернеиу компоненту обработчик событий, который инициирует эту передачу.


    У дочернего компонета создаём своё событие - outToParent (объект класса EventEmitter ), декорируя его декоратором @Output.

    Создадим в дочернем компоненте метод - sendToParent() . Его задача: передать событие родительскому объекту (метод emit()).

    Передано это событие будет через Angular объект - $event.

    Таким образом, созданное нами событие - outToParent произойдёт в тот момент, когда сработает sendToParent()и его (события) содержимое можно будет получить из $event.


    Дочерний компонент

    import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-inoutcomponent', templateUrl: './inoutcomponent.component.html', styleUrls: ['./inoutcomponent.component.css'] }) export class InoutcomponentComponent implements OnInit { @Input() public inFromParent: string; @Output() public outToParent = new EventEmitter(); constructor() { } ngOnInit() { } sendToParent() { this.outToParent.emit('Child sent this message to parent...'); } }


    Привяжем обработчик событий - click к кнопке в шаблоне дочернего компонента и по этому клику вызовем метод sentToParent, который в свою очередь включит событие outToParent:

    Шаблон дочернего компонента

    <h1>This is child component:</h1> <h3>{{inFromParent}}</h3> <br> <button (click)='sendToParent()'>Click to send data!</button> <br>


    Стиль дочернего компонента

    * {
    color: green;
    }



    Родительский компонент получает данные события методом, который мы в нём создали - getNessage()

    import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'app'; public string1 = <string> 'Data from parent...'; public string2 = ''; changeChildData() { this.string1 += ' Changed '; } receiveFromChild(evnt){ this.string2 = evnt; } }



    Шаблон родительского компонента (outToParent - новое событие, которое мы создали)

    <h1>This is parent component:</h1> <button (click)='changeChildData()'>Change child data </button> <hr> <strong>{{string2}}</strong> <app-inoutcomponent (outToParent)='receiveFromChild($event)' [inFromParent]='string1'></app-inoutcomponent>


    До клика



    После клика



    Декоратор @Component, свойства - inputs, outputs


    Вместо использования декораторов свойств - @Input и @Outpur можно использовать свойства декоратора класса - @Component (inputs, outputs).


    import { Component, OnInit, EventEmitter } from '@angular/core'; // import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-inoutcomponent', templateUrl: './inoutcomponent.component.html', styleUrls: ['./inoutcomponent.component.css'], inputs: ['inFromParent'], outputs:['outToParent'] }) export class InoutcomponentComponent implements OnInit { // @Input() public inFromParent: string; inFromParent: string; // @Output() public outToParent = new EventEmitter(); outToParent = new EventEmitter(); constructor() { } ngOnInit() { } sendToParent() { this.outToParent.emit('Child sent this message to parent...'); } }


    Но Angular рекомендуют использовать @Input и @Output 

    https://angular.io/guide/styleguide#style-05-12)%20(use-output-property-decorator

    style 05-12






  • Встроенные директивы Angular (Angular built-in directives)

    Примеры


    app.modules.ts


    import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { StudentsComponent } from './students/students.component'; @NgModule({ declarations: [ AppComponent, StudentsComponent ], imports: [ BrowserModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }



    StudentsComponent

    import { Component, OnInit } from '@angular/core'; import { StudentsInterface } from '../students-interface'; @Component({ selector: 'app-students', templateUrl: './students.component.html', styleUrls: ['./students.component.css'] }) export class StudentsComponent implements OnInit { students: StudentsInterface[]; constructor() { } ngOnInit() { this.students = [ { name: 'Anna', id: 1234567, age: 22, course: 'Angular' }, { name: 'Haim', id: 987654, age: 18, course: 'WEB' }, { name: 'Yossy', id: 456687456, age: 44, course: 'C' }, { name: 'Vasily', id: 1234567, age: 22, course: 'PHP' }, { name: 'Bob', id: 14312554, age: 37, course: 'Photoshop' }, { name: 'Bob', id: 657856784567, age: 37, course: 'WEB' }, ]; } }



    StudentsInterface

    export interface StudentsInterface { name: string; id?: number; age: number; course: string; }



    students.component.html


    <h1>Students</h1> <hr> <h2>Names -all</h2> <ng-container *ngFor='let student of students; let n = index;'> <p>{{n}} : {{student.name}}</p> </ng-container> <hr> <h2>WEB students</h2> <ul *ngFor='let stud of students'> <li *ngIf='stud.course === "WEB"'>{{stud.course}} -> {{stud.name}}</li> </ul> <hr> <h2>Colored list</h2> <ul *ngFor='let studnt of students'> <ng-container [ngSwitch]='studnt.course'> <div style='color:red' *ngSwitchCase='"WEB"'>Name: {{studnt.name}}, Age: {{studnt.age}}, Course: {{studnt.course}}, Id: {{studnt.id}}</div> <div style='color:green' *ngSwitchCase='"PHP"'>Name: {{studnt.name}}, Age: {{studnt.age}}, Course: {{studnt.course}}, Id: {{studnt.id}}</div> <div style='color:blue' *ngSwitchCase='"C"'>Name: {{studnt.name}}, Age: {{studnt.age}}, Course: {{studnt.course}}, Id: {{studnt.id}}</div> <div style='color:lightgray' *ngSwitchDefault>Name: {{studnt.name}}, Age: {{studnt.age}}, Course: {{studnt.course}}, Id: {{studnt.id}}</div> </ng-container> </ul>






  • Примеры Angular директив

    (Angular built in directives)



    <H1>Students</H1> <table> <tr> <th>N</th> <th>Name</th> <th>Age</th> <th>Course</th> </tr> <tr *ngFor='let student of students; let n = index'> <td>{{n+1}}</td> <td>Name: {{student['Name']}}</td> <td>Age: {{student['Age']}}</td> <td>Course: {{student['Course']}}</td> </tr> </table> <hr> <h1>WEB students</h1> <table> <tr> <th>N</th> <th>Name</th> <th>Age</th> <th>Course</th> </tr> <ng-container *ngFor='let item of students; let n = index'> <tr *ngIf="item['Course'] == 'WEB'"> <td>{{n+1}}</td> <td>Name: {{item['Name']}}</td> <td>Age: {{item['Age']}}</td> <td>Course: {{item['Course']}}</td> </tr> </ng-container> </table> <hr> <ng-container *ngFor='let student of students'> <div *ngIf="student['Age'] >= 20; then adult; else child">this is ignored</div> <ng-template #adult>Adult: {{student['Name'] + ' Age:' + student['Age'] }}<br></ng-template> <ng-template #child>Child: {{student['Name'] + ' Age:' + student['Age'] }}<br></ng-template> </ng-container> <hr> <ng-container *ngFor='let student of students; let n = index'> {{n + 1}} <ng-container [ngSwitch]='student["Course"]'> <div *ngSwitchCase='"WEB"' style='color:red'> WEB : {{student['Name']}}<br> </div> <div *ngSwitchCase='"PHP"' style='color:green'> PHP : {{student['Name']}}<br> </div> <div *ngSwitchCase='"C++"' style='color:blue'> C++ : {{student['Name']}}<br> </div> </ng-container> </ng-container>



    import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-students', templateUrl: './students.component.html', styleUrls: ['./students.component.css'] }) export class StudentsComponent implements OnInit { students = []; constructor() { } ngOnInit() { this.students = [ {'Name': 'Ivan', 'Age': '25', 'Course': 'WEB'}, {'Name': 'Haim', 'Age': '20', 'Course': 'PHP'}, {'Name': 'Kate', 'Age': '19', 'Course': 'C++'}, {'Name': 'Ivan', 'Age': '25', 'Course': 'WEB'}, {'Name': 'Haim', 'Age': '30', 'Course': 'PHP'}, {'Name': 'Kate', 'Age': '19', 'Course': 'C++'}, {'Name': 'Ivan', 'Age': '16', 'Course': 'WEB'}, {'Name': 'Haim', 'Age': '33', 'Course': 'PHP'}, {'Name': 'Kate', 'Age': '10', 'Course': 'C++'} ]; console.log(this.students); } }






  • Angular HttpClient - работа с HTTP запросами



    Использование HttpClient


    Angular HttpClient - класс, который предоставляет пользователям удобный интерфейс для работы с HTTP запросами, он базируется на использовании XMLHttpRequest объекта браузера - .

    Для использования HttpClient API нужно импортировать модуль HttpClientModule (обычно - в app.module.ts):


    import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { HttpClientModule } from '@angular/common/http'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, HttpClientModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }



    После этого можно использовать HttpClient в классе Angular - приложений, импортируя HttpClient и подключая его через dependancy injection. Например, создав сервис, который будет отвечать за передачу данных но HTTP:


    import { Injectable } from '@angular/core'; import { HttpClient} from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class Http1Service { constructor(private myHttp: HttpClient) { } }


    Объект, созданный из HttpClient (в примере выше - myHttp), поддерживает методы:


    • get
    • post
    • put
    • delete
    • patch
    • head
    • jsonp


    Для тестирования приложения Angular, которое работает с HttpClient можно использовать, например:

    • Angular модуль:  HttpClientTestingModule, 
    • специальные online сервисы, типа: http://jsonplaceholder.typicode.com/ , https://www.jsontest.com/, 
    • nodeJs (Angular in-memory web API: npm i angular-in-memory-web-api@0.5.3 --save ).
    • Или любой другой WEB server, который будет обрабатывать HTTP запросы.


      Простой пример - get()

      Простой пример использования метода get() Http клиента - файл на локальном диске, который содержит данные в формате JSON.

      Создадим айл с именем: myData.json

      [ {"Name": "Bob", "Age": "23", "Course": "WEB"}, {"Name": "Anna", "Age": "33", "Course": "PHP"}, {"Name": "Yony", "Age": "27", "Course": "Angular"} ]

      Расположим его в папке src/assets/data

      Создадим компонент get-data

      import { Component, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Component({ selector: 'app-get-data', templateUrl: './get-data.component.html', styleUrls: ['./get-data.component.css'] }) export class GetDataComponent implements OnInit { fileData: any; constructor(private myHttp: HttpClient) { } ngOnInit( ) { this.myHttp.get('assets/data/myData.json').subscribe( (reslt) => { console.log(this.fileData = reslt) }); } }


      this.myHttp - наш объект типа HttpClient

      this.myHttp.get('assets/data/myData.json') - метод get() этого объекта, который получает в качестве рапаметра - URL , где расположен источник данных в формате JSON

      Этот метод возвращает в качестве результата Angular объект типа Observable. Это - массив данных, элементв которого формируются асинхронно, динамически, в результате запроса.

      У этого объекта есть метод - subscribe(), который позволяет получать данные в формате JSON.

      Мы задали (в формате arrow - function) параметр этого меода - функцию с аргументом reslt, которая выполнится по эго окончании (call-back function). В переменную reslt subscribe поместит результат выполнения.

       this.myHttp.get('assets/data/myData.json').subscribe((reslt) => {console.log(reslt)});

      Этот результат можно запомнить в переменной класса и использовать в шаблоне компонента (при интерпретации данных в примере используется Angular pipe - json для форматирования данных ).

      Шаблон:

      {{fileData | json }}


      this.myHttp.get('assets/data/myData.json').subscribe((reslt) => {console.log(this.fileData = reslt)});


      Результат: 


      PHP - server side

      Далее , для тестирования используем на сервере PHP - программу (myAngularGetV2.php).

      Программа на PHP запущена локально (URL =  http://angularhttp/myAngularGetV2.php).

      Программа получает запрос от Angular и отвечает на него.

      Рассмотрим метод HttpClient.get().


      Код программы:

      <?php header('Access-Control-Allow-Origin: http://localhost:4200'); header('Content-type: application/json'); header('Access-Control-Allow-Methods: GET'); $outstr = ' [ {"Name": "Bob", "Age": "23", "Course": "WEB"}, {"Name": "Anna", "Age": "33", "Course": "PHP"}, {"Name": "Yony", "Age": "27", "Course": "Angular"} ] '; echo($outstr); ?>


      Эта программа получает запрос от Angular - приложения и отдаёт ему нужные данные (данные эти в нашем случае хранятся в переменной $outstr, в реальной жизни, скорее всего PHP берёт их из базы данных)

      Результат - такой же, как при чтении из файла на диске.


      Передача данных от Angular на сервер по get()

      Усложним немного запрос от Angular к серверу.

      Для этого в метод get() добавим ещё один допустимый параметр - params и передадим через него на сервер имя пользователя.

      Вызов get() примет вид:

      this.myHttp.get( myUrl, {params: { 'Name': 'Anna' }} ).subscribe( (reslt) => {console.log(this.fileData = reslt)} ); }

      Мы передаём теперь на сервер по методу get параметр Name со значением Anna

      Теперь сервер получает запрос с параметром. PHP - программа на сервере может этот запрос проанализиолвать и дать ответ в соответствии с этим параметром.

      В нашем случае заведём в программе массив данных - $students и в этом массиве найдём того, чьё имя соответствует параметру запроса.

      В ответ сервера (JSON ) вставим данные только найденного студента.


      PHP:

      <?php header('Access-Control-Allow-Origin: http://localhost:4200'); header('Content-type: application/json'); header('Access-Control-Allow-Methods: GET'); $stud = $_GET['Name']; $students = Array( Array("Name"=> "Bob", "Age"=> "23", "Course"=> "WEB"), Array("Name"=> "Anna", "Age"=> "33", "Course"=> "PHP"), Array("Name"=> "Yony", "Age"=> "27", "Course"=> "Angular"), ); foreach($students as $student){ if($student['Name'] == $stud){ $outstr = '[{ '; $outstr .= '"Name": "'; $outstr .= $student['Name']; $outstr .= '", "Age": "'; $outstr .= $student['Age']; $outstr .= '", "Course": "'; $outstr .= $student['Course']; $outstr .= '" }]'; } } echo($outstr); ?>


      В переменную $stud получили искомого студента

      В цикле foreach перебираем массив, ищем нужного.

      Если нашли - формируем строке $outstring ответ в формате JSON и командой echo отправляем ответ (до этого функциями header мы сформировали необходимый набор HTTP заголовков ).


      Компонент:

      import { Component, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Component({ selector: 'app-get-data', templateUrl: './get-data.component.html', styleUrls: ['./get-data.component.css'] }) export class GetDataComponent implements OnInit { fileData: any; constructor(private myHttp: HttpClient) { } ngOnInit( ) { const: myUrl = 'http://angularhttp/myAngularGetV2.php'; this.myHttp.get( myUrl, {params: { 'Name': 'Anna' }} ).subscribe( (reslt) => {console.log(this.fileData = reslt)} ); } }


      Шаблон (используем Angular - pipe json для ворматирования данных):

      {{ getData | json }}


      Результат



  • Структура проекта

    my-post.service.ts - сервис, который обменивается данными с сервером

    my-post-interface.ts - структура данных 

    my-post.component.ts - компонент, который этот сервис использует


    Сервис (Injectable )

    import { Injectable, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { MyPostInterface } from './my-post-interface'; @Injectable({ providedIn: 'root' }) export class MyPostService { myData = []; myUrl = 'http://angularhttp/myAngularPostV4.php'; constructor(private myHttp: HttpClient) { } sendRequest() { this.myHttp.post(this.myUrl, {observe: 'body', responseType: 'json'}) .subscribe({ next: data => console.log('Request N: ' , this.myData.push(data)), error: err => console.error('Error: ' + err), complete: () => console.log('Complete'),}); return this.myData; } }


    Интерфейс

    export interface MyDataInterface { id: number; name: string; title: string; msg: string; }


    Компонент

    import { Component, OnInit } from '@angular/core'; import { MyPostService } from '../my-post.service'; @Component({ selector: 'app-my-post', templateUrl: './my-post.component.html', styleUrls: ['./my-post.component.css'] }) export class MyPostComponent implements OnInit { myDataArray = []; constructor(private connectToServer: MyPostService) { } ngOnInit() { } getData() { this.myDataArray = this.connectToServer.sendRequest(); } }


    app-module

    import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { HttpClientModule } from '@angular/common/http' import { MyPostService } from './my-post.service'; import { MyPostComponent } from './my-post/my-post.component'; @NgModule({ declarations: [ AppComponent, MyPostComponent ], imports: [ BrowserModule, HttpClientModule ], providers: [MyPostService], bootstrap: [AppComponent] }) export class AppModule { }


    Шаблон компонента


    import { Component, OnInit } from '@angular/core'; import { MyPostService } from '../my-post.service'; @Component({ selector: 'app-my-post', templateUrl: './my-post.component.html', styleUrls: ['./my-post.component.css'] }) export class MyPostComponent implements OnInit { myDataArray = []; constructor(private connectToServer: MyPostService) { } ngOnInit() { } getData() { this.myDataArray = this.connectToServer.sendRequest(); } }


    Стили компонента


    TABLE { border-collapse: collapse; width: 100%; } TABLE TH { color: red; font-size: 1.2rem; } TABLE TH, TABLE TD { border: 1px solid lightgray; padding: 5px; } .testbutton { color: #14396A; text-shadow: 1px 1px 0px #7CACDE; box-shadow: 1px 1px 1px #BEE2F9; padding: 10px 25px; border-radius: 10px; border: 2px solid #3866A3; background: #63B8EE; background: linear-gradient(to bottom, #63B8EE, #468CCF); } .testbutton:hover { color: #F00; background: #468CCF; background: linear-gradient(to bottom, #468CCF, #63B8EE); }



    Результат - до запроса к серверу



    После запроса


    Поиск данных на сервере

    Пошлём серверу имя пользователя (Anna), чтобы получить полную информации о нём

    Сервис

    import { Injectable, OnInit } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { MyPostInterface } from './my-post-interface'; @Injectable({ providedIn: 'root' }) export class MyPostService { constructor(private myHttp: HttpClient) { } sendRequest() { const myUrl = 'http://angularhttp/myAngularPostV4.php'; let myData = []; this.myHttp.post(myUrl, {observe: 'body', responseType: 'json'}) .subscribe({ next: data => console.log('Server requested: ' , myData.push(data)), error: err => console.error('Error: ' + err), complete: () => console.log('Complete'),}); return myData; } getUserData() { const myUrl = 'http://angularhttp/myAngularPostV5.php'; const myHeaders = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); let myData = []; this.myHttp.post(myUrl, {name : 'Anna'}, {headers: myHeaders, observe: 'body', responseType: 'json'}) .subscribe({ next: data => console.log('Server requested: ' , myData.push(data)), error: err => console.error('Error: ' + err), complete: () => console.log('Complete'),}); return myData; } }



    Компонент

    import { Component, OnInit } from '@angular/core'; import { MyPostService } from '../my-post.service'; @Component({ selector: 'app-my-post', templateUrl: './my-post.component.html', styleUrls: ['./my-post.component.css'] }) export class MyPostComponent implements OnInit { allUsers = []; foundUser = []; constructor(private connectToServer: MyPostService) { } ngOnInit() { } getAllData() { this.allUsers = this.connectToServer.sendRequest(); } getUserData() { this.foundUser = this.connectToServer.getUserData(); } }



    Шаблон компонента

    <h1>POST test component</h1> <hr> <button class='testbutton' (click)='getAllData()'>Request all data from server</button> <table> <tr> <th>ID</th> <th>Name</th> <th>Position</th> <th>Remarks</th> </tr> <tr *ngFor='let str of allUsers[0]'> <td>{{str['id']}}</td> <td>{{str['name']}}</td> <td>{{str['title']}}</td> <td>{{str['msg']}}</td> </tr> </table> <hr> <button class='testbutton' (click)='getUserData()'>Get user data</button> <table> <tr> <th>ID</th> <th>Name</th> <th>Position</th> <th>Remarks</th> </tr> <tr *ngFor='let str of foundUser[0]'> <td>{{str['id']}}</td> <td>{{str['name']}}</td> <td>{{str['title']}}</td> <td>{{str['msg']}}</td> </tr> </table> <hr>



    app.module.ts
    import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { HttpClientModule } from '@angular/common/http' import { MyPostService } from './my-post.service'; import { MyPostComponent } from './my-post/my-post.component'; @NgModule({ declarations: [ AppComponent, MyPostComponent ], imports: [ BrowserModule, HttpClientModule ], providers: [MyPostService], bootstrap: [AppComponent] }) export class AppModule { }


    Результат 



    Server side

    Используется  Apache на локальном компьютере. Адрес сервера: http://angularhttp/ Запросы обрабатывает PHP - программа myAngularPostV4.php.

    Формат данных и способ их интерпретации зависит от HTTP заголовков (руфвукы), которые выставлены и в Angular 

    const myHeaders = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');

    и 

    {observe: 'body', responseType: 'json'}

    и в PHP

    header('Content-type: application/x-www-form-urlencoded; charset=UTF-8');

    PHP должен интерпретировать то, что посылает Angular через метод subscribe() объекта Observable. Если при посылке меняем формат, то и в PHP его надо менять.


    Программа PHP получает запрос от Angular и в ответ посылает строку с данными (в формате JSON) - myAngularPostV4.php

    <?php header('Access-Control-Allow-Origin: http://localhost:4200'); header('Content-type: application/json'); header("Access-Control-Allow-Headers: *"); header('Access-Control-Allow-Methods: POST'); $outstr = '[{ "id" : 1000, "name" : "Anna", "title" : "Manager", "msg" : "Sales department" }, { "id" : 1001, "name" : "Bob", "title" : "Technician", "msg" : "Server support team" }, { "id" : 1002, "name" : "Alex", "title" : "WEB developer", "msg" : "Corporate web development team" } ]'; echo($outstr); ?>



    Эхо - тест (получили запрос - отдали то, что получили) - myAngularPostV3.php

    <?php header('Access-Control-Allow-Origin: http://localhost:4200'); header('Content-type: application/json'); header("Access-Control-Allow-Headers: *"); header('Access-Control-Allow-Methods: POST'); $_POST = json_decode(file_get_contents('php://input'), true); $id = $_POST['id']; $name = $_POST['name']; $title = $_POST['title']; $msg = $_POST['msg']; $outstr = '[{ '; $outstr .= '"id": "'; $outstr .= $id; $outstr .= '", "name": "'; $outstr .= $name; $outstr .= '", "title": "'; $outstr .= $title; $outstr .= '", "msg":"'; $outstr .= $msg; $outstr .= '" }]'; echo($outstr); ?>


    Найти пользователя по имени (myAngularPostV5.php)


    <?php //if($_SERVER['HTTP_ORIGIN'] == "http://localhost:4200") header('Access-Control-Allow-Origin: http://localhost:4200'); header("Access-Control-Allow-Headers: *"); header('Content-type: application/x-www-form-urlencoded; charset=UTF-8'); header('Access-Control-Allow-Methods: POST'); $data = json_decode(file_get_contents("php://input")); $name = $data->name; $users = Array(); $users[] = Array ("id"=> 1111, "name"=> "Bob", "title"=> "Manager", "msg"=> "CEO"); $users[] = Array("id"=> 222, "name"=> "Nik", "title"=> "Sales", "msg"=> "Corporate sales dept"); $users[] = Array("id"=> 4444, "name"=> "Anna", "title"=> "Technician", "msg"=> "Network support team"); $users[] = Array("id"=> 5, "name"=> "Haim", "title"=> "HR", "msg"=> "Human resource"); $users[] = Array("id"=> 76, "name"=> "Ronald", "title"=> "CA", "msg"=> "Accounting") ; foreach($users as $key => $user){ if($user['name'] == $name){ $outstr = '[{ '; $outstr .= '"id": "'; $outstr .= $user['id']; $outstr .= '", "name": "'; $outstr .= $user['name']; $outstr .= '", "title": "'; $outstr .= $user['title']; $outstr .= '", "msg": "'; $outstr .= $user['msg']; $outstr .= '" }]'; } } error_log( $outstr); echo($outstr); ?>



    Асинхронный поиск по мере ввода имени

    В этом примере в окне браузера (в поле INPUT ) вводится имя сотрудника. По мере ввода (событие - keyup ) имя пересылается по POST серверу и проверяется PHP программой на сервере. Если PHP не нашёл сотрудника по имени (ищем в массиве сотрудников), он выдаёт сообщение (также в формате JSON)  

    Сервис


    import { Injectable, OnInit } from '@angular/core'; import { HttpClient, HttpHeaders} from '@angular/common/http'; import { MyPostInterface } from './my-post-interface'; import { PostOptionsInterface } from './post-options-interface'; @Injectable({ providedIn: 'root' }) export class MyPostService { constructor(private myHttp: HttpClient) { } sendRequest() { const myUrl = 'http://angularhttp/myAngularPostV4.php'; let myData = []; this.myHttp.post(myUrl, {observe: 'body', responseType: 'json'}) .subscribe({ next: data => console.log('Server request: ' , myData.push(data)), error: err => console.error('Error: ' + err), complete: () => console.log('Complete'),}); return myData; } getSingleUser() { const myUrl = 'http://angularhttp/myAngularPostV5.php'; const myHeaders = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); let myData = []; this.myHttp.post(myUrl, {name : 'Anna'}, {headers: myHeaders, observe: 'body', responseType: 'json'}) .subscribe({ next: data => console.log('Server request: ' , myData.push(data)), error: err => console.error('Error: ' + err), complete: () => console.log('Complete'),}); return myData; } findUser(userName){ const httpHdr = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); const postUrl = 'http://angularhttp/myAngularPostV6.php'; const postBody = {name : userName}; let myData = []; this.myHttp.post(postUrl, postBody, { headers: httpHdr, observe: 'body', responseType: 'json' }) .subscribe({ next: data => console.log('Server requested: ' , myData.push(data)), error: err => console.error('Error: ' + err), complete: () => console.log('Complete'),}); return myData; } }


    Компонент


    import { Component, OnInit } from '@angular/core'; import { MyPostService } from '../my-post.service'; @Component({ selector: 'app-my-post', templateUrl: './my-post.component.html', styleUrls: ['./my-post.component.css'] }) export class MyPostComponent implements OnInit { allUsers = []; singleUser = []; foundUser = []; constructor(private connectToServer: MyPostService) { } ngOnInit() { } getAllData() { this.allUsers = this.connectToServer.sendRequest(); } getSingleUser() { this.singleUser = this.connectToServer.getSingleUser(); } findUser(evnt){ console.log(evnt.target.value); this.foundUser = this.connectToServer.findUser(evnt.target.value); } removeHint(evnt){ evnt.target.value = ''; evnt.target.select(); } }


    HTML - шаблон компонента


    <h1>POST test component</h1> <hr> <button class='testbutton' (click)='getAllData()'>Request all users data from server</button> <table> <tr> <th>ID</th> <th>Name</th> <th>Position</th> <th>Remarks</th> </tr> <tr *ngFor='let str of allUsers[0]'> <td>{{str['id']}}</td> <td>{{str['name']}}</td> <td>{{str['title']}}</td> <td>{{str['msg']}}</td> </tr> </table> <hr> <button class='testbutton' (click)='getSingleUser()'>Get data of user: Anna</button> <table> <tr> <th>ID</th> <th>Name</th> <th>Position</th> <th>Remarks</th> </tr> <tr *ngFor='let str of singleUser[0]'> <td>{{str['id']}}</td> <td>{{str['name']}}</td> <td>{{str['title']}}</td> <td>{{str['msg']}}</td> </tr> </table> <hr> <input type='text' (keyup)='findUser($event)' (mouseenter)='removeHint($event); ' name='' value='Type case-sensitive user name here...'> <table> <tr> <th>ID</th> <th>Name</th> <th>Position</th> <th>Remarks</th> </tr> <tr *ngFor='let str of foundUser[0]'> <td colspan=4 *ngIf="str['id'] == 0; else found">{{str['name']}} {{str['title']}} {{str['msg']}}</td> <ng-template #found> <td>{{str['id']}}</td> <td>{{str['name']}}</td> <td>{{str['title']}}</td> <td>{{str['msg']}}</td> </ng-template> </tr> </table> <hr>



    CSS - стили компонента



    BUTTON, INPUT { margin: 10px 0px; } INPUT { width: 98.5%; padding: 5px; background-color: #EFEFEF; } TABLE { border-collapse: collapse; width: 100%; } TABLE TH { color: red; font-size: 1.2rem; } TABLE TH, TABLE TD { border: 1px solid lightgray; padding: 5px; } .testbutton { color: #FFF; text-shadow: 1px 1px 0px #7CACDE; box-shadow: 1px 1px 1px #BEE2F9; padding: 10px 25px; border-radius: 10px; border: 2px solid #3866A3; background: #63B8EE; background: linear-gradient(to bottom, #63B8EE, #468CCF); } .testbutton:hover { color: #F00; background: #468CCF; background: linear-gradient(to bottom, #468CCF, #63B8EE); }



    app.module.ts


    import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { HttpClientModule } from '@angular/common/http' import { MyPostService } from './my-post.service'; import { MyPostComponent } from './my-post/my-post.component'; @NgModule({ declarations: [ AppComponent, MyPostComponent ], imports: [ BrowserModule, HttpClientModule ], providers: [MyPostService], bootstrap: [AppComponent] }) export class AppModule { }




    Интерфес - структура данных: my-post-interface.ts

    export interface MyPostInterface { id: number; name: string; title: string; msg: string; }



    Server side: PHP - ищет сотрудника по имени (http://angularhttp/myAngularPostV6.php)

    <?php // if($_SERVER['HTTP_ORIGIN'] == "http://localhost:4200") header('Access-Control-Allow-Origin: http://localhost:4200'); header('Content-type: application/x-www-form-urlencoded; charset=UTF-8'); header('Access-Control-Allow-Methods: POST'); $data = json_decode(file_get_contents("php://input")); $name = $data->name; $users = []; $users[] = ["id"=> 1111, "name"=> "Bob", "title"=> "Manager", "msg"=> "CEO"]; $users[] = ["id"=> 222, "name"=> "Nik", "title"=> "Sales", "msg"=> "Corporate sales dept"]; $users[] = ["id"=> 4444, "name"=> "Anna", "title"=> "Technician", "msg"=> "Network support team"]; $users[] = ["id"=> 5, "name"=> "Haim", "title"=> "HR", "msg"=> "Human resource"]; $users[] = ["id"=> 76, "name"=> "Ronald", "title"=> "CA", "msg"=> "Accounting"] ; $outstr = '[{ "id":"00000", "name":"User", "title":"not", "msg":"found" }]'; foreach($users as $key => $user){ if($user['name'] == $name){ $outstr = '[{ '; $outstr .= '"id": '; $outstr .= $user['id']; $outstr .= ', "name": "'; $outstr .= $user['name']; $outstr .= '", "title": "'; $outstr .= $user['title']; $outstr .= '", "msg": "'; $outstr .= $user['msg']; $outstr .= '" }]'; } } error_log($name); error_log( $outstr); echo($outstr); ?>


    Server side: PHP выводит всех сотрудников ((http://angularhttp/myAngularPostV4.php))


    <?php header('Access-Control-Allow-Origin: http://localhost:4200'); header('Content-type: application/x-www-form-urlencoded; charset=UTF-8'); header("Access-Control-Allow-Headers: *"); header('Access-Control-Allow-Methods: POST'); $users = []; $users[] = ["id"=> 1111, "name"=> "Bob", "title"=> "Manager", "msg"=> "CEO"]; $users[] = ["id"=> 222, "name"=> "Nik", "title"=> "Sales", "msg"=> "Corporate sales dept"]; $users[] = ["id"=> 4444, "name"=> "Anna", "title"=> "Technician", "msg"=> "Network support team"]; $users[] = ["id"=> 5, "name"=> "Haim", "title"=> "HR", "msg"=> "Human resource"]; $users[] = ["id"=> 76, "name"=> "Ronald", "title"=> "CA", "msg"=> "Accounting"] ; $outstr = json_encode($users, JSON_PRETTY_PRINT); echo($outstr); ?>


    Результат - вывели всех сотрудников




    Результат при начале набора в поле ввода




    Результат - нашлось имя



    PHP - error log (при каждом событии keyup PHP получает имя и пишет для отладки в error log полученное имя и строку для отправки в Angular ):

    [01-Jun-2018 15:43:53 UTC] R [01-Jun-2018 15:43:53 UTC] [{ "id":"00000", "name":"User", "title":"not", "msg":"found" }] [01-Jun-2018 15:43:53 UTC] R [01-Jun-2018 15:43:53 UTC] [{ "id":"00000", "name":"User", "title":"not", "msg":"found" }] [01-Jun-2018 15:43:54 UTC] Ron [01-Jun-2018 15:43:54 UTC] [{ "id":"00000", "name":"User", "title":"not", "msg":"found" }] [01-Jun-2018 15:43:54 UTC] Ron [01-Jun-2018 15:43:54 UTC] [{ "id":"00000", "name":"User", "title":"not", "msg":"found" }] [01-Jun-2018 15:43:54 UTC] Rona [01-Jun-2018 15:43:54 UTC] [{ "id":"00000", "name":"User", "title":"not", "msg":"found" }] [01-Jun-2018 15:43:55 UTC] Ronal [01-Jun-2018 15:43:55 UTC] [{ "id":"00000", "name":"User", "title":"not", "msg":"found" }] [01-Jun-2018 15:43:55 UTC] Ronald [01-Jun-2018 15:43:55 UTC] [{ "id": 76, "name": "Ronald", "title": "CA", "msg": "Accounting" }]









  • Angular - навигация по сайту (Angular routing)

    При помощи  Routing - модуля Angular позволяет организовать привычную навигацию по страничкам сайта:

    • если ввести в адресной строке браузера IRI нужной странички, то она откроется
    • если кликнуть по ссылке на нужную страничку сайта (меню сайта, другие внутренние ссылки) , то Angular откроет её в окне браузера
    • если пользоваться кнопками браузера НАЗАД, ВПЕРЁД, то мы будем перемещаться по истории посещённых страничек сайта.

    Сконфигурируем сайт, который будет состоять из: одной главной странички - home, страничек  About, Contacts и специальной странички, которая будет открываться в том случае, если посетитель сайта пытается перейти на несуществующую страничку - NotFound.

    Для этого:

    • генерируем новый проект с опцией - routing (ng new routing-test1 --routing) в дополнение к стандарной конфигурации проекта появится модуль app-routing.module.ts
    • генерируем модуль с названием header для меню сайта
    • генерируем модули для каждой нужной странички сайта (home, about, contacts, notFound)
    • проверяем наличие тега <base href="/"> в файле index.html, что обязательно для работы router 
    • конфигурируем router - модуль (ссылки и их привязки к компонентам)
    • конфигурируем шаблон сайта в модуле app.component

    Angular создаёт app-routing.module.ts

    import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; const routes: Routes = []; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }


    Генерируем нужные компоненты:

    ng g c not-found

    ng g c contacts

    ng g c home

    ng g c header

    ng g c about


    Все компоненты и Router импортированы в app.module - проверяем:

    import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { HomeComponent } from './home/home.component'; import { HeaderComponent } from './header/header.component'; import { AboutComponent } from './about/about.component'; import { ContactsComponent } from './contacts/contacts.component'; import { NotFoundComponent } from './not-found/not-found.component'; @NgModule({ declarations: [ AppComponent, HomeComponent, HeaderComponent, AboutComponent, ContactsComponent, NotFoundComponent ], imports: [ BrowserModule, AppRoutingModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }


    Конфигурируем - app.component

    import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { }


    Его HTML шаблон:

    <div id='wrapper'> <app-header></app-header> <router-outlet></router-outlet> </div>

    Через него определяем место (placeholder ) в окне браузера для компонента-меню (<app-header></app-header>)

    И для меняющихся компонентов-страничек ( <router-outlet></router-outlet>)

    Его стили:

    #wrapper { display: grid; grid-template-rows: auto auto; grid-template-columns: 1fr; }


    Компоненты страничек практически ничем, в нашем примере, друг от друга не отличаются (только текстом в HTML).

    import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-about', templateUrl: './about.component.html', styleUrls: ['./about.component.css'] }) export class AboutComponent implements OnInit { constructor() { } ngOnInit() { } }


    HTML

    <h1>About Us</h1>


    Компонент header - это меню сайта (он показывает кнопки меню и привязывает их к тем путям URI , которые мы задали в раутере, он появляется на каждой страничке):

    import { Component} from '@angular/core'; @Component({ selector: 'app-header', templateUrl: './header.component.html', styleUrls: ['./header.component.css'] }) export class HeaderComponent { constructor() { } }


    HTML

    Директивы routerLink привязывают тег A к пути, который задан в модуле Router (константа routes )

    Директивы routerLinkActive присваивают элементам A класс стилей myActive в тот момент, когда ссылка активна.

    <div id='navBlock'> <a class='menuItem' routerLink='/home' routerLinkActive="myActive">Home</a> <a class='menuItem' routerLink='/about' routerLinkActive="myActive">About</a> <a class='menuItem' [routerLink]="['/contacts']" routerLinkActive="myActive">Contacts</a> </div>


    Стили

    Селектор  .menuItem[class*='myActive'] описывает стиль для активной ссылки. Класс myActive она получает по директиве routerLinkActive

    #navBlock { display: grid; grid-template-columns: repeat(3, minmax(auto, 300px)); grid-template-rows: 1fr; justify-content: center; align-content: space-between; border-bottom: 1px solid #aaa; } .menuItem { display: inline-block; text-align: center; padding: 10px 0px; margin: 10px; border: 1px solid #FFF; font-weight: bold; font-size: 1.2re; border-radius: 5px; box-shadow: 0px 2px 5px 1px rgba(100, 100, 100, 0.294); } .menuItem:hover { border-color: red; box-shadow: 0px 5px 10px 3px rgba(100, 100, 100, 0.294); } .menuItem[class*='myActive'] { color: red ! important; } .menuItem:visited { color: blue; } A { text-decoration: none; }




    Конфигурируем router.

    Конфигурируем в константе routes массив ссылок. Каждый элемент массива - путь и компонент, который к этому пути привязан.

    Элемент массива {path: '', redirectTo: '/home', pathMatch: 'full'} переадресовывает ссылки в корень сайта на страничку home

    Элемент массива {path: '**', component: NotFoundComponent} переадресовывает все странички, путь к которым не соответствует фильтрам пути в предыдущих элементах, на страничку NotFound 

    import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { AboutComponent } from './about/about.component'; import { ContactsComponent } from './contacts/contacts.component'; import { HomeComponent } from './home/home.component'; import { NotFoundComponent } from './not-found/not-found.component'; const routes: Routes = [ {path: '', redirectTo: '/home', pathMatch: 'full'}, {path: 'home', component: HomeComponent}, {path: 'about', component: AboutComponent}, {path: 'contacts', component: ContactsComponent}, {path: '**', component: NotFoundComponent} ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }



    Результат :





  • Angular Service


    Angular service - это специализированный компонент, который предназначен для того, чтобы предоставлять другим компонентам какие-либо общие данные.

    Генерируем сервис, пользуясь Angular CLI

    ng g service my-serv1

    Получаем его шаблон:  

    import { Injectable } from '@angular/core'; @Injectable() export class MyServ1Service { constructor() { } }


    Импортируем его в app.module.ts, чтобы он был доступен всем компонентам проекта

    import { MyServ1Service } from './my-serv1.service';

    Регистрируем его там же в providers, чтобы можно было его использовать во всех дочерних компонентов через Angular Dependancy Injection

    providers: [ MyServ1Service ],

     


    import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; import { CollapseModule } from 'ngx-bootstrap/collapse'; import { PopoverModule } from 'ngx-bootstrap/popover'; import { AppComponent } from './app.component'; import { Comp1Component } from './comp1/comp1.component'; import { MyServ1Service } from './my-serv1.service'; @NgModule({ declarations: [ AppComponent, Comp1Component ], imports: [ PopoverModule.forRoot(), CollapseModule.forRoot(), BsDropdownModule.forRoot(), BrowserModule ], providers: [ MyServ1Service ], bootstrap: [AppComponent] }) export class AppModule { }




    Добавляем метод getSomething():  

    import { Injectable } from '@angular/core'; @Injectable() export class MyServ1Service { constructor() { } getSomething(){ return "222222222"; } }



    Используем в компоненте - без Dependancy injection (не рекомендуется)

    import {MyServ1Service} from '../my-serv1.service' ; import { Component} from '@angular/core'; @Component({ selector: 'comp1', template: ` <h1>Comp1Component</h1> {{courses}} ` }) export class Comp1Component { courses; constructor (){ let servData = new MyServ1Service(); this.courses = servData.getSomething(); } }



    Используем в компоненте через Dependency injection (в этом случае constructor (service: MyServ1Service) создаёт внутри класса переменную с именем service , которая является объектом (instance) класса MyServ1Service )

    import {MyServ1Service} from '../my-serv1.service' ; import { Component} from '@angular/core'; @Component({ selector: 'comp1', template: ` <h1>Comp1Component</h1> {{courses}} ` }) export class Comp1Component { courses; constructor (service: MyServ1Service){ this.courses = service.getSomething(); } }


    И в app.module.ts добавляем импорт 

    import { MyServ1Service } from './my-serv1.service';

    и 

    providers: [ MyServ1Service ],


    весь файл 

    import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; import { CollapseModule } from 'ngx-bootstrap/collapse'; import { PopoverModule } from 'ngx-bootstrap/popover'; import { AppComponent } from './app.component'; import { Comp1Component } from './comp1/comp1.component'; import { MyServ1Service } from './my-serv1.service'; @NgModule({ declarations: [ AppComponent, Comp1Component ], imports: [ PopoverModule.forRoot(), CollapseModule.forRoot(), BsDropdownModule.forRoot(), BrowserModule ], providers: [ MyServ1Service ], bootstrap: [AppComponent] }) export class AppModule { }