如何在经过清理的输入上书写?

时间:2019-06-03 14:37:45

标签: angular typescript html-sanitizing

我有一个小应用,其中我收到一个带有一些隐藏单词的问题,像这样写下来:

publishOn()

接收到此字符串后,每个 The {0} {1} {2} his {3} off 字符串都必须替换为用户输入的正确答案。为此,我创建了以下代码:

HTML部分

{x}

打字稿功能

<div *ngFor="let question of questionsArray">
     ---- some stuff ----
    <div [innerHTML]="createQuestion(question)"></div>
     ---- some stuff ----
</div>

我还像这样在构造函数中添加了createQuestion(question: string): SafeHtml { let innerHtml = ''; let words = question.split(' '); for (let index = 0; index < words.length; index++) { const element = words[index]; if (element.indexOf('{') >= 0) { innerHtml += '<input type="text" name="test"></input>'; } else { innerHtml += element; } } return this.sanitizer.bypassSecurityTrustHtml(innerHtml); }

DomSanitizer

它工作正常并绘制如下输入:

enter image description here

但是我不能在输入上写任何东西。我想也许 constructor(private sanitizer: DomSanitizer) {} 可能无法正常工作,因为我没有按照建议的here使用任何byPassSecurityHtml。但是,由于我需要以动态方式创建它,并且需要在DOM中将它称为foreach 问题,所以我不知道如何正确使用它...

有人可以帮我吗?

3 个答案:

答案 0 :(得分:1)

DOM字符串的问题是,即使它们是由浏览器呈现的,Angular也不会将它们视为视图绑定模板的一部分。解决此问题的最佳方法是使用一个数组,该数组定义应如何呈现模板,如下所示:

createQuestion(question: string) {
const template = question.match(/[A-Za-z]+|{\d}/g) // <-- [ 'The', '{0}', '{1}', '{2}', 'his', '{3}', 'off' ]
                  .map(match => match[0] === '{' ? { type: 'input', value: ''}
                  : { type: 'string', value: match })

return template;
}

createQuestion方法接受模板字符串,并使用正则表达式将其分成[ 'The', '{0}', '{1}', '{2}', 'his', '{3}', 'off' ]形式的多个部分,然后将其传递给map方法,该方法为每个部分生成一个统一的对象。任何具有字符串“ {”的部分都被视为输入的占位符,因此它将变成{ type: 'input', value: '' }形式,任何文本都变成{ type: 'text', value: 'text value here' }形式,以便我们以后可以遍历此数组并使用* ngIf有条件地呈现文本或输入。

这是为您提供的示例字符串生成的模板。

template = [
  { type: 'text', value: 'The' },
  { type: 'input', value: '' }
  { type: 'input', value: '' }
  { type: 'input', value: '' }
  { type: 'text', value: 'his' }
  { type: 'input', value: '' }
  { type: 'text', value: 'off' }
]

使用此模板,您可以像这样创建一个值绑定角度模板,

<div *ngFor="let template of questionsArray.map(q => createQuestion(q))">
     ---- some stuff ----
    <div *ngFor="let section of template">
    <input *ngIf="section.type === 'input'" ([ngModel])="section.value" />
    <span *ngIf="section.type === 'text'">{{ section.value }}</span>
    </div>
     ---- some stuff ----
</div>

外部*ngFor指令循环遍历所有已使用.map(q => createQuestion(q))转换为模板的不同问题。内部的*ngFor指令循环遍历模板的每个部分,并根据每个部分的span属性生成inputtype。如果类型为text,则显示跨度。如果类型为input,并且显示输入时将ngModel绑定到value属性。

答案 1 :(得分:0)

这不是您应该使用Angular的方式。

在Angular中,您不会自己操纵DOM。您应该让框架为您处理。

对于您的问题,我认为最好的解决方案是在原始字符串上使用管道,以免对其进行修改。

Here is some stackblitz so that you can see it in action

答案 2 :(得分:0)

基于@Avin Kavish的目的,我找到了这个最简单的解决方案:

打字稿部分

createQuestion(question: QuestionDto): Array<string> {
    let words = question.correctAnswer.split(' ');
    return words;
}

返回一个包含所有分隔元素的字符串数组。它返回以下内容:

 ["The", "{0}", "{1}", "{2}", "his", "{3}", "off"]

HTML部分 在UI部分中,我检查了内容数组,以便决定是否绘制输入或文本。

<div *ngFor="let question of questionsArray">
    <div *ngFor="let word of createQuestion(question); index as i">
       <input *ngIf="word.includes('{'); else elseBlock"
           id="word-{{i}}"
           class="form-control"
           type="text" />
           <ng-template #elseBlock>{{ word }}</ng-template>
    </div> 
 </div>