Tips for composing content on a sanitized input?

In my small application, I have a feature where a question is displayed with certain words hidden and needs to be filled in by the user. The format of the question looks like this:

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

To achieve this functionality, I wrote the following code:

HTML section

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

Typescript function:

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);
}

I have also included the DomSanitizer in the constructor as shown below:

 constructor(private sanitizer: DomSanitizer) {}

Although the inputs are being rendered correctly, I am facing an issue where I am unable to type anything in the input field. I suspect that the bypassSecurityHtml method might not be working correctly without using a Pipe as suggested here. Since the dynamic creation of inputs based on each question prevents me from using it within a pipe, I am seeking assistance on how to resolve this issue...

If anyone could provide some guidance, it would be greatly appreciated.

Answer №1

One issue with DOM strings is that Angular does not recognize them as part of the template for view binding, despite being rendered by the browser. To address this problem, a solution is to utilize an array to define how the template should be rendered, as demonstrated below:

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

return template;
}

The createQuestion function takes a template string and breaks it down into segments using a regular expression method. Each segment is then transformed into a uniform object structure - placeholders for input are converted to { type: 'input', value: '' }, while text segments become

{ type: 'text', value: 'text value here' }
. This allows for conditional rendering of either text or input using *ngIf directives later on.

For instance, for the provided exemplary string, the following template is generated:

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

This template can then be utilized to create an angular template with bound values:

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

The outer *ngFor loop iterates through all the transformed templates derived from different questions using .map(q => createQuestion(q)). The inner *ngFor loop cycles through each section of the template and displays either a span or an input based on the type property of each section. If the type is text, a span is displayed. If the type is input, an input field is displayed with ngModel linking to the value property.

Answer №2

Using Angular in this way is not recommended.

Angular is designed to manage the DOM manipulation for you, so it's best to let the framework handle that task.

If you're facing an issue, consider using a pipe on your original string instead of directly modifying it.

Check out this live demo on Angular to see it in action

Answer №3

After reviewing the purpose of @Avin Kavish, I have discovered a straightforward solution:

Typescript segment

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

This function returns an array of strings with each element separated. The output looks like this:

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

HTML section For the user interface, I examine the content array to determine whether to display an input field or the text.

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

React JS displayed the string of /static/media/~ instead of rendering its markdown content

When I looked at the material UI blog template, I created my own blog app. I imported a markdown file using import post1 from './blog-posts/blog-post.1.md'; Next, I passed these properties to this component like so: <Markdown className=" ...

Combining various POST requests by matching the common value in each array. (Angular)

Here are the two different sets of data: "statusCode": 200, "data": [ { "color": { "id": "1111", "name": null, "hex&quo ...

The power of Typescript shines in its ability to ensure type safety when working with conditional

I am struggling with typing a simple function in Typescript that takes a union type and a boolean as parameters. Here is the code snippet: type A = 'a' | 'A'; function f(a: A, b: boolean): string { if (b) { switch (a) { ...

Tips for sending an Angular http post request including both data and an image:

When making a post request in Angular, I typically send data (such as 'product' data) using an object like this: product: any = {}; // filled with properties (code, barcode, name, description...) and then include it in the request: return this.h ...

Ways to efficiently update the API_BASE_URL in a TypeScript Angular client generated by NSwag

Is it possible to dynamically change the API_BASE_URL set in my TypeScript client generated by NSWAG? I want to be able to utilize the same client with different API_BASE_URLs in separate Angular modules. Is this achievable? Thank you for your assistance. ...

Proper method for determining return type through the use of `infer`

I need to find out the return type based on input values, like in the code below: type ReturnType<S> = { array: S extends 'number' ? number[] : S extends 'string' ? string[] : never; value: S extends 'number' ? n ...

Discovering ways to optimize argument type declarations in TypeScript

If we consider having code structured like this: function updateById( collection: Record<string, any>[], id: number, patch: Record<string, any> ): any[] { return collection.map(item => { if (item.id === id) { return { ...

When utilizing express-handlebars to render, the error message "req.next() is not a valid function

Trying to display the login page of a web application. Developed using TypeScript, node.js, express, and express-handlebars The code being executed is as follows: import exphbs = require("express-handlebars"); import cookieParser = require(&quo ...

The ngOnInit lifecycle hook is not triggered by the Angular routerLink

In the component.ts file, you will find the ngOnInit function as shown below: ngOnInit() { this.locationService.getLocation().subscribe( locations => { this.locations = locations; }); } <a [routerLink]="['/locations-list&apo ...

Allow TypeScript function parameters to accept multiple elements from an enumeration

Enumerating my options. export enum Selection { CHOICE_ONE = 'one', CHOICE_TWO = 'two', CHOICE_THREE = 'three', CHOICE_FOUR = 'four', } I am looking to design a function that accepts an array, but re ...

Having some trouble while attempting to set up the next-auth@beta package due to an error

Currently encountering the following error message: code EUNSUPPORTEDPROTOCOL Unsupported URL Type "workspace:": workspace:* I have made sure to update my node to the most recent recommended version. In a previous project, I successfully instal ...

Generating an instance of a class by using the class name as a string

Before jumping to conclusions, please take a moment to read the following: In addition to TypeScript, my issue also involves Angular2. Main Goal I am in need of a method in app.component.ts that can take a string (Class Name) and generate an instance of ...

What is the process for establishing the default type for an Activity Entity in Microsoft Dynamics?

Currently in the process of restructuring a portion of script code associated with the Fax Activity Entity within Microsoft Dynamics. Within the script code, the following can be found: document.getElementById("regardingobjectid").setAttribute("defaulttyp ...

How should a string be properly converted to JSON format?

I am encountering an issue with converting the following string to JSON format const banner = " { "banners": [ { "startDate": "02/26/2021", "endDate": "12/25/2021","content": "Important ...

Is Angular mat-icon undergoing a "transformation"?

Overview: The material icon I am using is the "+" sign to represent adding a new item on a webpage. While it displays correctly in English, the Spanish version of the site shows "ñ" instead. Inquiry: Should I leave the tags empty or remove the translati ...

How can the dependencies object be extracted from the package.json file in an Angular project?

Scenario: I am managing multiple Angular applications within the same project. Whenever I need to upgrade an npm package, I find myself having to manually update the package.json files in each application. While I attempted a mono repo approach, it did not ...

Guide to implementing user authentication in .NET Core 2.1 Angular application

As I navigate through Visual Studio 2017, I find that the Individual User Account option is disabled in the Angular template. This leaves me wondering how to implement user authentication without this feature. Being new to VS 2017 and .Net Core 2.1, I sear ...

I'm looking for a solution to reorganize my current state in order to display the image URL

My React component, which also utilizes TypeScript, is responsible for returning a photo to its parent component: import React, { useEffect, useState } from "react"; import axios from "axios"; export const Photo = () => { const [i ...

Confirm the presence of a particular sub collection within Firebase/Firestore by returning true

Can you confirm if the sub-collection named 'categories' exists within the users collection in Firestore? Please return true if it exists and false if it does not. ...

`I'm having difficulty transferring the project to Typescript paths`

I posted a question earlier today about using paths in TypeScript. Now I'm attempting to apply this specific project utilizing that method. My first step is cloning it: git clone <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cf ...