angular11学习(十八) angular img 404的问题 Form 查找后台的 Form 输入字母转大写 服务的使用 创建库 主模块子模块关于NavigationEnd 问题 发现一个有趣的问题 双向数据绑定css变量 自定义指令 Rxjs 错误处理 angular 不变形的重要性

angular11学习(十八)
angular img 404的问题
Form 查找后台的
Form 输入字母转大写
服务的使用
创建库
主模块子模块关于NavigationEnd 问题
发现一个有趣的问题
双向数据绑定css变量
自定义指令
Rxjs 错误处理
angular 不变形的重要性

必须放在src/assets

请使用相对路径

Form 查找后台的

以前

fg.controls['name']
fg.controls['address'].controls['city']

现在

fg.get('address.city')
fg.get(['address', 'street'])

禁用

fg.controls['name'].disable();
fg.controls['city'].disable({ onlySelf: true }); // 不更新父级

解除 enabled

Form 输入字母转大写

NgModel

<input type="text" [(ngModel)]="num" appMyDirective>


import {Directive, HostListener} from '@angular/core';
import {NgModel} from '@angular/forms';

@Directive({
  selector: '[appMyDirective]'
})
export class MyDirectiveDirective {
  constructor(private model: NgModel) {

  }

  @HostListener('input', ['$event.target'])
  ngModelChanges(e) {
    let a=e.value.toUpperCase()
    // 写入
    this.model.valueAccessor.writeValue(a)
    // 更新
    this.model.viewToModelUpdate(a)
  }

}

formControlName

<form  [formGroup]="myForm" (ngSubmit)="onSubmit()">
  <label>
    firstName: <input type="text" formControlName="firstName">
  </label>
  <label>
    lastName: <input type="text" formControlName="lastName">
  </label>
  <div formGroupName="address">
    <label>
      address1: <input type="text" formControlName="address1">
    </label>
    <label>
      address2: <input type="text" formControlName="address2" >
    </label>
  </div>
</form>
 public myForm: FormGroup;
  public str:string;

  constructor( private fb: FormBuilder) {
    this.myForm = this.fb.group({
      firstName: [''],
      lastName: [''],
      address: this.fb.group({
        address1: [''],
        address2: [''],
      })
    });
    this.myForm.valueChanges.subscribe(e => {
      if(this.str!==this.myForm.get('firstName').value){
        this.myForm.get('firstName').setValue(e.firstName.toUpperCase(),{onlySelf:true})
      }
      this.str=this.myForm.get('firstName').value;
    });
  }

升级版本

  <label>
      address2: <input type="text" formControlName="address2" appMyDirective>
    </label>

export class MyDirectiveDirective {
  constructor(private injector: Injector) { }

  @HostListener('input', ['$event.target'])
  ngModelChanges(e) {
    let a = e.value.toUpperCase();
    // 这个代码好牛逼,拿到注射器实例
    let {control} = this.injector.get(NgControl);
    control.setValue(a)
    // 更新规则
    control.updateValueAndValidity();
  }
}

注册器的相关使用

新建一个服务

import {Injectable} from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class HelloService {

  constructor() {
  }

  say(from: string) {
    console.log(`hello ${from}`);
    return true;
  }
}

组件中直接查找使用

 ngAfterViewInit() {
    const service=inject(HelloService)
    service.say('AppModule')
  }

服务的使用

useClass

告诉我们使用了那个类

import {Injectable} from '@angular/core';

@Injectable({
  providedIn: 'root',
  useClass:HelloService
})
export class HelloService {

  constructor() {
  }

  say(from: string) {
    console.log(`hello ${from}`);
    return true;
  }
}

进行使用
  constructor(private helloService:HelloService) {
    this.helloService.say('bbbb')
  }

创建库

ng g  library  my-lib

projects 里面有个 my-lib 项目文件夹

package.json

    "ng-packagr": "^10.0.0",

app.module

import {MyLibModule} from '../../projects/my-lib/src/lib/my-lib.module'

@NgModule({
    imports: [
            MyLibModule
    ]
})

页面的使用

<lib-my-lib></lib-my-lib>

主模块子模块关于NavigationEnd 问题

同事今天遇到一个问题主模块app.componentRouter.event 事件无法检测某个模块的NavigationEnd 事件

最终通过跟同事一起分析的解决思路是

主模块应该把 router.event 放在 constructor 
而子模块的东西应该放在生命周期里面`ngOnInit`

发现一个有趣的问题

如果判断clickdrag 事件

 let a=document.querySelector('#aaa');
    merge(
      fromEvent(a,'mousedown').pipe(mapTo(1)),
      fromEvent(a,'mousemove').pipe(mapTo(2)),
    ).pipe(
      sample(fromEvent(a,'mouseup'))// 促发条件:松开鼠标促发
    ).subscribe(flag=>{
      if (flag == 1) {
        console.log('click');
      }else if (flag == 2) {
        console.log('drag');
      }
    })

双向数据绑定css变量

<input type="number" [(ngModel)]="x">
<p [style.--num]="x">hello world</p>

p{
  font-size:calc(var(--num)*1px)
}

x = 20;

我们发现 x=20 变量了css变量进行操作

自定义指令

<div appChColor>
  hello world
</div>

@Directive({
  selector: '[appChColor]'
})
export class ChColorDirective {

  constructor(
    private el: ElementRef,
    private renderer: Renderer2
  ) {
    this.changeColor('red')
  }

  changeColor(color: string) {
    this.renderer.setStyle(this.el.nativeElement, 'color', color)
  }
  // click 的时候修改颜色
  @HostListener('click')
  foo(){
    this.changeColor('green')
  }
}

Rxjs 错误处理

  this.http.get('/assets/data.json--').pipe(
      catchError(error=>of([]))
    ).subscribe(res=>{
      console.log(res);
    })
  • 我们正在向catchError运算符传递一个函数,这是错误处理函数
  • 错误处理函数不会立即被调用,通常,通常不会被调用
type TypeArrays = {
  data: Array<any>
}

export class UserComponent implements OnInit {

  constructor() {}

  loading: boolean;
  arr: Array<any>

  ngOnInit(): void {
    this.http.get<TypeArrays>('/assets/data.json').pipe(
      finalize(() => {
        this.loading = !!this.arr.length;
      })
    ).subscribe(res => {
      this.arr = res.data;
    })
  }

}

angular11学习(十八)
angular img 404的问题
Form 查找后台的
Form 输入字母转大写
服务的使用
创建库
主模块子模块关于NavigationEnd 问题
发现一个有趣的问题
双向数据绑定css变量
自定义指令
Rxjs 错误处理
angular 不变形的重要性

angular 不变形的重要性

<app-dev-card-v1 class="card" *ngFor="let dev of devs" [dev]="dev">
</app-dev-card-v1>

ngOnChanges生命周期检测值发生变化

set 输入属性,ngOnChanges生命周期挂钩的替代方法,并在传递新值时执行

@Input() 
set dev(val: Dev) {
    this._dev = val;
    this.seniorityLevel = this.getSeniorityLevel();
  }

如果您不能轻松地切换到不变的更新模式,则解决陈旧数据呈现问题的一种方法是使用getter即时计算视图模型数据

export class DevCardV5Component {
  @Input() public dev: Dev;

  public get seniorityLevel(): SeniorityLevel {
    console.log("seniorityLevel getter called");

    return this.getSeniorityLevel();
  }

  private get skill(): number {
    return this.dev.skill;
  }
}

但是,您仍然不能使用该组件的OnPush更改检测策略。而且,在每个更改检测周期都将调用getter

另一种选择是在ngDoCheck生命周期挂钩中执行计算,它被认为是不得已的方法,因为与getter相似,它在每个变更检测周期内都会被调用

  ngDoCheck() {
    this.seniorityLevel = this.getSeniorityLevel();
  }