使用 Angular 和 ANYWHERE 将元素动态添加到可编辑的 div [英] Dynamically add elements to the editable div with Angular and ANYWHERE

查看:26
本文介绍了使用 Angular 和 ANYWHERE 将元素动态添加到可编辑的 div的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我正在创建一个 HTML 界面,用户应该能够在其中编写文本并将其作为通知推送到我们的移动应用.

我正面临一些使用 Angular 5 处理文本和动态插入元素的问题;

文本可以包含特殊元素,例如:电话号码、位置和网站 URL.这些特殊元素将通过按下打开对话框的按钮插入,并为每个显示其特定字段,例如用于位置的谷歌地图和用于 Web URL 和手机的输入字段.以这种方式实现它是为了在保存按钮上捕获经度、纬度和电话号码,以便将它们作为按钮添加到设备上接收到的推送中.

无论如何,除了在 Web 界面的 div 内动态添加特殊元素的跨度的方式之外,上述内容已经实现并且可以成功工作.添加的跨度必须有一个类和一个单击事件以再次显示对话框以修改数据.也可以根据用户的选择将它们插入到大 div 内的任何位置.

下面是上面描述的图片.

蓝色跨度是应该在内容可编辑 div 中动态添加的跨度,可以填充大约 450 个字符.

那么如何解决该问题并启用在内容可编辑的 div 中添加带有图标的可点击和设计跨度的功能,并能够在最后阶段检索数据?

我的代码如下,但适用于特定/预定义的位置:

Message.html

 

<ng-容器#vc></ng-容器>

Message.ts

 @ViewChild('vc', {read: ViewContainerRef}) 目标:ViewContainerRef;createSpanPhone(spanIDNumber, phoneDescription, phoneValue ){//这里的span Phone是在div之外动态创建的让 phoneComponent = this.cfr.resolveComponentFactory(PhoneComponent);this.componentRef = this.target.createComponent(phoneComponent);}

PhoneComponent.ts

 import { Component } from '@angular/core';从@fortawesome/free-solid-svg-icons"导入{faPhone};@成分({选择器:我的手机",模板:'<fa-icon[图标]=faPhone"class =faSpanIcon"></fa-icon><span class="phoneDesc"data-attr="EN">hello</span><span class="phoneVal";><b>12346</b></span></span>'})导出类 PhoneComponent {faPhone = faPhone;//尝试图标构造函数(){}测试(){console.log("Hiiii");//尝试点击事件}}

ViewContainerRef 已成功填充,但我需要在上面的 div (id=myMessage) 中填充跨度,而不是在预定义的位置.

解决方案

如果你的文本是简单的文本(没有不能用 括起来的 html 标签,-I want表示允许例如 ,但不允许

- 您可以创建一个组件,如

@Component({选择器:html-content",模板:`<span class="inline";[innerHTML]=值"></span>`})导出类 HtmlComponent {@Input() 值;构造函数(){}}

类似的指令

@Directive({ 选择器:[内容]"})导出类 ContentDirective {@Input() 设置内容(textHtml: string) {this.viewContainerRef.clear();如果 (!textHtml) 返回//如果不是以 .或空格,加一个空格if (textHtml.slice(-1)!=" && textHtml.slice(-1)!=".")textHtml+=""//获取单词"//const 部分 = textHtml.match(/\ ?\S+\ |\ ?\S+\./gi);const 部分 = textHtml.match(/<?[^\r\n\t\f\v<]+\ ?/gi);零件.forEach(h => {让空间=假;let search = h.replace(/[\ .;,:]/gi, "")让 arg=null;//允许以这种方式向组件传递参数,例如//<phone=arguments - 小心!参数不能包含空格//if (search.match(/<phone=.+/)){arg=search.split("=")[1].split(">")[0]搜索=<电话>"}if (search.match(/<location=.+/)){arg=search.split("=")[1].split(">")[0]搜索=<位置>"}开关(搜索){案例<电话>":案例<位置>":const 工厂 =搜索==<电话>"?this.componentFactoryResolver.resolveComponentFactory(电话组件): this.componentFactoryResolver.resolveComponentFactory(位置组件);const phone=this.viewContainerRef.createComponent(factory);//如果我们的组件有@Input() arg";(phone.instance as any).arg=arg||"";休息;默认:const factoryHtml = this.componentFactoryResolver.resolveComponentFactory(html组件);const html = this.viewContainerRef.createComponent(factoryHtml);html.instance.value = h;空间=真;休息;}//这允许在组件后写入空格或点.if (!space && h.match(/.+>[\;,:.]/gi)) {const factoryDot = this.componentFactoryResolver.resolveComponentFactory(html组件);const html = this.viewContainerRef.createComponent(factoryDot);//我们检查组件后面是否有一个,"或;"或:"或"."html.instance.value = h.slice(h.indexOf(>")+1)}});//仅用于检查零件console.log(textHtml, 部分);}构造函数(私有 viewContainerRef: ViewContainerRef,私有 componentFactoryResolver: ComponentFactoryResolver) {}}

您可以看到 stackblitz 没有保修

So, I am creating an HTML interface where user should be able to write a text and push it as a notification to our mobile app.

I am facing some troubleshoots with the text and the dynamic inserted elements using Angular 5;

The text can contain special elements like: phone number, Location and website URL. Those special elements will be inserted by pressing on a button that opens a dialog, and for each one its specific fields are displayed, like google maps for location and input fields for Web URL and mobile Phone. It is implemented this way in order to capture longitude, latitude and phone numbers on save button in order to add them as buttons to the received push on the devices.

Anyway, the above is implemented and could work successfully except the way of adding dynamically spans of special elements inside the div of the web interface. Spans added must have a class and a click event to display again the dialog in order to modify the data. Also they can be inserted anywhere inside the big div depending on user's choice.

Below is the image of above description.

The blue spans, are the ones that should be added dynamically inside the content editable div that can be filled by around 450 characters.

So how to solve the issue and enable the feature of adding clickable and designed spans with icons inside a content editable div, and be able in a final stage to retrieve data?

My code is the below, working but for a specific/predefined position:

Message.html

      <div id="myMessage" contenteditable="true" dir="ltr" [innerHTML]="contentEN | safeHtml" 
      style=" height: 80px;border: 1px solid #c1c1c1; padding: 7px;">
      </div>
      
      <ng-container  #vc>           
      </ng-container>

Message.ts

      @ViewChild('vc', {read: ViewContainerRef}) target: ViewContainerRef;
      
      createSpanPhone(spanIDNumber, phoneDescription, phoneValue ){
      
          // here the span Phone is created dynamically outside the div
          let phoneComponent = this.cfr.resolveComponentFactory(PhoneComponent);
          this.componentRef = this.target.createComponent(phoneComponent);
      }

PhoneComponent.ts

    import { Component } from '@angular/core';
    import { faPhone } from '@fortawesome/free-solid-svg-icons';

    @Component({
       selector: 'my-phone',
       template: '<span contenteditable="false" (click) = "test()" class="BAN_Tags_IN_Text"> <fa-icon 
                  [icon]="faPhone" class="faSpanIcon"> </fa-icon> <span class="phoneDesc" 
                  data-attr="EN">hello</span> <span class="phoneVal" ><b>12346</b></span>
                   </span>'
      })

   export class PhoneComponent  {
      faPhone = faPhone; // trying the icon

      constructor(){    
      }

     test(){
       console.log("Hiiii"); // trying the click event
     }
   }  

The ViewContainerRef is filled successfully but I need to fill spans in the div above (id=myMessage) and not in a predefined position.

解决方案

if your text are simple text (don't has html tags that can not enclosed by <span>, -I want to mean that is allowed e.g. <i> or <b>, but not <p> - you can create a component like

@Component({
  selector: "html-content",
  template: `
    <span class="inline" [innerHTML]="value"></span>
  `
})
export class HtmlComponent {
  @Input() value;
  constructor() {}

}

A directive like

@Directive({ selector: "[content]" })
export class ContentDirective {
  @Input() set content(textHtml: string) {
    this.viewContainerRef.clear();
    if (!textHtml) return
    //If not end with . or space, add an space
    if (textHtml.slice(-1)!=" " && textHtml.slice(-1)!=".")
      textHtml+=" "

    //gets the "words"
    //const parts = textHtml.match(/\ ?\S+\ |\ ?\S+\./gi);

     const parts = textHtml.match(/<?[^\r\n\t\f\v< ]+\ ?/gi);
    parts.forEach(h => {
      let space = false;
      let search = h.replace(/[\ .;,:]/gi, "")
      let arg=null;

      //to allow pass arguments to the components in the way, e.g.
      //     <phone=arguments -be carefull! the arguments can not contains spaces
      //     
      if (search.match(/<phone=.+/))
      {
        arg=search.split("=")[1].split(">")[0]
        search="<phone>"
      }
      if (search.match(/<location=.+/))
      {
        arg=search.split("=")[1].split(">")[0]
        search="<location>"
      }
        
      switch (search) {
        case "<phone>":
        case "<location>":
          const factory =
            search == "<phone>"
              ? this.componentFactoryResolver.resolveComponentFactory(
                  PhoneComponent
                )
              : this.componentFactoryResolver.resolveComponentFactory(
                  LocationComponent
                );

          const phone=this.viewContainerRef.createComponent(factory);
          //if our component has "@Input() arg"
          (phone.instance as any).arg=arg||"";
          break;
        
        default:
          const factoryHtml = this.componentFactoryResolver.resolveComponentFactory(
            HtmlComponent
          );
          const html = this.viewContainerRef.createComponent(factoryHtml);
          html.instance.value = h;
          space = true;
          break;
      }
      //this allow write space or dot after the component.
      if (!space && h.match(/.+>[\ ;,:.]/gi)) {
        const factoryDot = this.componentFactoryResolver.resolveComponentFactory(
          HtmlComponent
        );
        const html = this.viewContainerRef.createComponent(factoryDot);
        //we check if, after the component we has a "," or ";" or ":" or ". "
        html.instance.value = h.slice(h.indexOf(">")+1)
      }
    });
    //just for check the parts
    console.log(textHtml, parts);
  }
  constructor(
    private viewContainerRef: ViewContainerRef,
    private componentFactoryResolver: ComponentFactoryResolver
  ) {}
}

You can see a stackblitz without warranty

这篇关于使用 Angular 和 ANYWHERE 将元素动态添加到可编辑的 div的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆