【问题标题】:How to write on a Sanitized input?如何在经过消毒的输入上书写?
【发布时间】:2019-06-03 14:37:45
【问题描述】:

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

 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 可能无法正常工作,因为我没有按照建议的here 使用任何Pipe。但是,由于我需要以动态方式创建它,因为它需要在我的 DOM 中调用 foreach question,所以我无法弄清楚如何正确使用它...

谁能帮帮我?

【问题讨论】:

    标签: angular typescript html-sanitizing


    【解决方案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 =&gt; createQuestion(q)) 转换为模板的不同问题。内部*ngFor 指令循环遍历模板的每个部分,并根据每个部分的type 属性生成spaninput。如果类型为text,则显示一个跨度。如果类型是 input 并且输入显示为 ngModel 绑定到 value 属性。

    【讨论】:

    • 有不清楚的地方吗?我会添加一些文字
    • 这是因为类型(我的是一个复杂的对象)。但我认为您的解决方案对我来说将是一个好的解决方案。让我再试一次:)
    • 谢谢阿尔文!我接受了您的回答并发布了我修改后的解决方案。但是您的回答与我的问题最接近,并且通过您的回答,我可以使它成为最有棱角的可能^^所以..非常感谢!
    【解决方案2】:

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

    在 Angular 中,您无需自己操作 DOM。您应该让框架为您处理。

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

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

    【讨论】:

    • 但是我有一个完全动态的问题列表,可能需要引入不同数量的输入...我知道我不应该修改 DOM 但是...我该怎么做以另一种方式?
    • @Sonhja 完全按照我的方式做?我刚刚为您提供了无需修改 Dom 的方法,现在只需根据您的情况调整它...
    • 我以前只需要回答一个问题时使用过这种方法。但是现在……我们不知道要解决的问题的确切数量。它是动态的并且来自非受控数据库:(所以这是我真正的问题。你使用它的方式,我在另一部分中完全一样,用户只需要回答一个。但是,如果我们有一个要回答的问题数量不定?如何创建 DOM 来定义所需的输入数量?
    • 听说过 ngFor 吗?
    • 这个答案没有解决基于用户输入模板生成动态表单的问题。
    【解决方案3】:

    基于@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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-10
      • 1970-01-01
      • 1970-01-01
      • 2013-01-03
      相关资源
      最近更新 更多