具有 contentEditable div 和 ngModel 支持的 Angular 2 表单

2024-01-08

我正在尝试使用 Angular 2 Forms,但不是使用input我想使用可编辑的div.

这有效:

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

但这会引发错误:

<div contentEditable="true" [(ngModel)]="value"></div>

TypeError:设置一个只有 getter 的属性

有没有办法将 div 与 Angular Forms 一起使用?我不想使用输入或文本区域


不是开箱即用的..

ngModel只能在支持它的元素上访问!

您可以创建指令或自定义输入组件。

无论如何,它必须实现这个接口ControlValueAccessor.

指示:

工作演示:https://plnkr.co/edit/12vAEFf2OBS3ERu9fhwk?p=preview https://plnkr.co/edit/12vAEFf2OBS3ERu9fhwk?p=preview

import {Directive, Component, NgModule, forwardRef, ViewChild, ElementRef, HostListener, Renderer} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import { FormsModule, ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Directive({
  selector: 'div[contentEditable]',
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => EditableDivDirective),
      multi: true
    }
  ]
})
export class EditableDivDirective implements ControlValueAccessor {

  constructor(private _elRef: ElementRef, private _renderer: Renderer) { }

  onChange() {
    if (this._onChange) {
      this._onChange(this._elRef.nativeElement.innerText);
    }
  }

  @HostListener('keyup', ['$event'])
  keyup(event: any) {
    this.onChange();
  }


  // ControlValueAccessor implementation
  // ====================================

  private _onChange = (_) => { }; // call it if your value changed..
  private _onTouched = () => { }; // call it "on blur" ..

  // will be called if a values comes in via ngModule !
  writeValue(val: any) {
    if (!val) val = '';

    this._renderer.setElementProperty(this._elRef.nativeElement, 'innerText', val);
  }

  registerOnChange(fn: (_: any) => void): void { this._onChange = fn; }
  registerOnTouched(fn: () => void): void { this._onTouched = fn; }
}

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <div contentEditable="true" [(ngModel)]="name">test test test</div>
    </div>
  `,
})
export class App {
  name:string;
  constructor() {
    this.name = 'Angular2'
  }
}

@NgModule({
  imports: [ BrowserModule, FormsModule ],
  declarations: [ App, EditableDivDirective ],
  bootstrap: [ App ]
})
export class AppModule {}

成分:

查看工作演示:https://plnkr.co/edit/XMSTrWSe3gN9iwVTBukz?p=preview https://plnkr.co/edit/XMSTrWSe3gN9iwVTBukz?p=preview

import {Component, NgModule, forwardRef, ViewChild, ElementRef} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import { FormsModule, ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  selector: 'my-name-input',
  template: `
    <div>
      <label>first name</label>
      <div #firstName contentEditable="true" (keyup)="onChange()">{{this._firstName}}</div>
      <br />
      <label>last name</label><input [(ngModel)]="_lastName"  (ngModelChange)="onChange()" />
    </div>
  `,
  providers: [ // IMPORTANT !!
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => MyCompleteNameInputComponent),
      multi: true
    }
  ]
})
export class MyCompleteNameInputComponent implements ControlValueAccessor {

  @ViewChild('firstName') editableDiv: ElementRef;

  private _firstName: string = '';
  private _lastName: string = '';

  onChange() {

    this._firstName = this.editableDiv.nativeElement.innerText;

    if (this._onChange) {
      this._onChange(this._firstName + ' ' + this._lastName);
    }
  }


  // ControlValueAccessor implementation
  // ====================================

  private _onChange = (_) => { }; // call it if your value changed..
  private _onTouched = () => { }; // call it "on blur" ..

  // will be called if a values comes in via ngModule !
  writeValue(val: any) {
    if (!val || !val.split) val = '';

    let splitted = val.split(' ');
    this._firstName = splitted[0] || '';
    this._lastName = splitted[1] || '';
  }

  registerOnChange(fn: (_: any) => void): void { this._onChange = fn; }
  registerOnTouched(fn: () => void): void { this._onTouched = fn; }
}

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <my-name-input [(ngModel)]="name"></my-name-input>
    </div>
  `,
})
export class App {
  name:string;
  constructor() {
    this.name = 'Angular2'
  }
}

@NgModule({
  imports: [ BrowserModule, FormsModule ],
  declarations: [ App, MyCompleteNameInputComponent ],
  bootstrap: [ App ]
})
export class AppModule {}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

具有 contentEditable div 和 ngModel 支持的 Angular 2 表单 的相关文章

  • 订阅内循环订阅?

    我目前正在与订阅内的 multiples forEach 订阅作斗争 我正在尝试检索对象列表 然后通过它们的 ID 检索它们的图像 目前我已经这样做了 this appTypeService get pipe map apps AppTyp
  • Angular 模板验证表单

    我正在研究表单验证 我正在使用模板驱动的验证表单 其编码如下 现在工作正常 但是当我尝试添加时 username ngModel and password ngModel 在创建验证类的输入中 它向我显示一个错误 也请找到该错误 div c
  • 在 Angular 5 中,如何从父组件访问动态添加的子组件?

    我正在开发一个 Ionic Angular 5 项目 我需要动态加载一些组件 继动态组件加载器示例 https angular io guide dynamic component loader在 Angular 文档中 我能够成功加载组件
  • RxJS 订阅内部订阅,每个级别返回值并存储到各自的变量中

    我知道已经有关于嵌套订阅的帖子 在这里 我们有 5 个级别的订阅操作 每个变量 operationId actionlistId componentId traceId 这里 API 正在调用 其功能如下 Step 1 订单模板 ID 为a
  • 使用 typescript、karma 和 jasmine 进行 RxJS Observable.timer 单元测试

    大家好 我对 Angular2 Karma 和 Jasmine 还比较陌生 目前我正在使用 Angular 2 RC4 Jasmine 2 4 x 我有一个 Angular 2 服务 它定期调用 http 服务 如下所示 getDataFr
  • 带纱线的 Angular CLI

    如何将 Angular Cli v6 0 3 的包管理器更改为yarn 我试过 ng set global packageManager yarn 但 Angular 说 get set 已被弃用 取而代之的是 config 命令 ng c
  • 有角度的动态背景图片

    在 html 模板中 我有这种带有动态图像的样式 div style background none width 200px height 150px div 它适用于网络浏览器和 Android 浏览器 但是 使用 style 的动态背景
  • 如何在 Angular Universal 中向 添加类?

    我们可以用户Rendered2在 Angular 应用程序的浏览器版本中 但它需要document body参考 它在服务器渲染上不可用 platform browser has Title and Meta组件 但我想有更多的控制权部分
  • 控制台未打开时无法加载资源:net::ERR_EMPTY_RESPONSE

    我正进入 状态 Failed to load resource net ERR EMPTY RESPONSE 如果控制台未打开 我的 api 调用会出错 然而如果控制台打开 则 api 调用工作正常 前端使用 Angular2 后端使用 N
  • setCenter 无法在 angular2-google-maps 中工作

    import GoogleMapsAPIWrapper from agm core import Component Input from angular core Component selector core map styleUrls
  • 传递多个参数或对象(单击)

    问题是将对象或多个参数从模板传递到组件 并使用它们将数据添加到 API 任务 service ts addTasks task Task Observable
  • 在 Y 轴上显示时间 - 气泡图

    我碰到Bubble Chart 最新补充 在ng2 图表 https valor software com ng2 charts 我试图根据 Y 轴的时间和 X 轴的值显示数据 我的数据就像 x 10 35 60 和 y 7 00 AM 和
  • 无法获取子 DOM 元素

    注 由于问题有点复杂 为了可读性对代码进行了抽象 We ve a
  • 如何导航到 Angular 7 中的锚点

    我已经在routingModule和所有路径中启用了anchorScrolling 但是当我单击链接时没有任何反应 nav bar component html div class sidenav a href class closeBtn
  • 如何在 Angular 中确定上一页 URL?

    假设我当前位于具有 URL 的页面上 user id 现在从本页导航到下一页 id posts 现在有没有办法让我可以检查之前的 URL 是什么 即 user id 以下是我的路线 export const routes Routes pa
  • Angular 5 - ag-grid 18.0.1 - 边缘崩溃

    我一直在到处搜索 但无法找到与此相关的任何信息 很可能是因为 ag grid update 18 x 是新的 无论如何 似乎在将 ag grid 从 17 1 1 更新到 18 0 1 后 任何带有 ag grid 的页面最终都会导致 ED
  • 如何在 Angular 2 karma jasmine 测试中从 JSON 文件加载模拟数据?

    我在写信业力茉莉花测试用例角2 我们遇到了在单独的 JSON 文件中模拟数据的需求 因为数据很大 希望确保代码整洁 为此我进行了很多搜索但没有找到合适的解决方案 我们已经使用以下方式模拟 HTTP 服务模拟后端 所以我们不能使用Angula
  • 将样式添加到 mat-autocomplete 的 mat-option

    我有这个 HTML代码在这里 https stackblitz com edit angular mat autocomplete with selected value vx1uqg file src 2Fapp 2Fautocomple
  • angular2 rc5 路由器服务单例

    我最近迁移到 Angular 2 RC 5 并将应用程序中的子模块转换为 NgModule 鉴于以下情况plunker https angular io resources live examples router ts plnkr htm
  • 使用占位符和 ngModel 动态生成输入元素

    我想以角度 2 动态生成输入元素 我有占位符标题数组和值数组 如下所示 在我的组件中 我有两个映射 如下所示 其中两个映射的键相同 将值映射到标题 const placeholderMap fullName Name value Produ

随机推荐