如何在经过消毒的输入上书写?

How to write on a Sanitized input?

我有一个小应用程序,我在其中收到一个问题,其中包含一些要写下的隐藏词:

 The {0} {1} {2} his {3} off

收到此字符串后,每个 {x} 字符串都必须替换为用户将填写正确答案的输入。为此,我创建了这段代码:

HTML部分

<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,如下所示:

 constructor(private sanitizer: DomSanitizer) {}

它工作正常并像这样绘制输入:

但是我不能在输入上写任何东西。我想 byPassSecurityHtml 可能无法正常工作,因为我没有按照 的建议使用任何 Pipe。但是,由于我需要以动态方式创建它,因为它需要在我的 DOM 中调用 foreach question,所以我不知道如何正确使用它...

任何人都可以帮助我吗?

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

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

对于你的问题,我认为最好的解决方案是在你的原始字符串上使用管道,而不是修改它。

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

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' }
]

使用此模板,您可以像这样创建值绑定 angular 模板,

<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 指令循环遍历模板的每个部分,并根据每个部分的 type 属性 生成 spaninput。如果类型是 text,则显示跨度。如果类型是 input 并且输入显示为绑定到 value 属性.

的 ngModel

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

打字稿部分

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

Return 一个包含所有分隔元素的字符串数组。它returns这个:

 ["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>