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

Ways to determine the types of props received by a function when the arguments vary for each scenario?

I have a specialized component that handles the majority of tasks for a specific operation. This component needs to invoke the onSubmit function received through props, depending on the type of the calling component. Below is an example code snippet show ...

How is it possible to inject various data services into individual components within an Angular2 application?

If you're working on a typical task management app called TaskMaster, There's a main TaskMaster component that offers a TaskManager service to handle all the task data. You've created a MainComponent that provides this TaskManager and inje ...

Changing a date format in typescript: Here is how you can easily convert a date from one

Using React with Typescript: I am currently working with a date picker from material-ui version 5. The date picker requires the date value to be in the format "yyyy-MM-dd". However, the API returns a Date object in the format "2022-01-12T00:00:00.000+00:0 ...

What is the best way to refresh my component following a delete operation in React?

I am currently facing an issue with using Sweetalert2 and React (tsx) where I am unsure how to refresh my item list after deleting methods. Below is the code snippet that I have for a button that implements these functions: function DeleteCard(item: DataI ...

Adjust the font size in Chart.js for improved resolution across all types of monitors (i.e. creating charts that are not specific

Everything is looking great on my chart with the labels perfectly displayed at the defined font size. However, I am facing an issue when viewing the chart in higher resolutions as the font sizes appear small. Is there a way to dynamically adjust all size-r ...

Angular 2: Enhancing User Experience with Pop-up Dialogs

Looking to implement a popup dialog that requests user input and returns the value. The popup component is included in the root component, positioned above the app's router outlet. Within the popup component, there is an open() method that toggles a ...

React-querybuilder experiencing issues with validator functionality

While utilizing the react-querybuilder, I have encountered an issue with field validation not functioning correctly. Upon reviewing this StackBlitz, it appears that when clicking on Rule and checking all fields, there are no errors present. export const fi ...

Utilize Material-UI in Reactjs to showcase tree data in a table format

I am currently tackling a small project which involves utilizing a tree structure Table, the image below provides a visual representation of it! click here for image description The table displayed in the picture is from my previous project where I made ...

Arrange the "See More" button in the Mat Card to overlap the card underneath

I'm currently working on a project that involves displaying cards in the following layout: https://i.stack.imgur.com/VGbNr.png My goal is to have the ability to click 'See More' and display the cards like this: https://i.stack.imgur.com/j8b ...

Are union types strictly enforced?

Is it expected for this to not work as intended? class Animal { } class Person { } type MyUnion = Number | Person; var list: Array<MyUnion> = [ "aaa", 2, new Animal() ]; // Is this supposed to fail? var x: MyUnion = "jjj"; // Should this actually ...

Just made the switch to Mongoose 5.12 and hit a snag - unable to use findOneAndUpdate with the $push operator

After upgrading to Mongoose 5.12 from 5.11 and incorporating Typescript, I encountered an issue with my schema: const MyFileSchema = new Schema<IMyFile>({ objectID: { type: String, required: true }, attachments: { type: Array, required: false ...

Leveraging Renderer in Angular 4

Understanding the importance of using a renderer instead of directly manipulating the DOM in Angular2 projects, I have gone through multiple uninstallations, cache clearings, and re-installations of Node, Typescript, and Angular-CLI. Despite these efforts, ...

Using Vue.js, learn how to target a specific clicked component and update its state accordingly

One of the challenges I'm facing is with a dropdown component that is used multiple times on a single page. Each dropdown contains various options, allowing users to select more than one option at a time. The issue arises when the page refreshes afte ...

Using Lerna with Docker for Next.js and GraphQL applications

Currently, I am working with lerna and everything runs smoothly locally. However, when I attempt to build the image and operate it through Docker, it does not function as expected. FROM node:16-alpine3.11 ENV NODE_ENV=production COPY . /app WORKDIR /app R ...

Is it possible for the link parameters array in Angular2 Routing to contain more than one element?

Currently delving into Angular2 on my own. According to the text I'm studying, when a user navigates to a feature linked to a route using the routerLink directive, the router employs both the link parameters array and the route configuration to constr ...

Error in AWS Cloud Development Kit: Cannot access properties of undefined while trying to read 'Parameters'

I am currently utilizing aws cdk 2.132.1 to implement a basic Lambda application. Within my project, there is one stack named AllStack.ts which acts as the parent stack for all other stacks (DynamoDB, SNS, SQS, StepFunction, etc.), here is an overview: im ...

The query fails to retrieve results for the specified date and the beginning of the month

I have encountered an issue with my query that is supposed to fetch values between the start and end of the month. Interestingly, when a record is entered on the first day of the month, it doesn't get returned in the query result. Only records entered ...

In <R>, what does R represent when it is wrapped around an observer of type Observer<R>? Would it result in a Subscription, Function, or void?

The Angularfire2 project is in the process of adding a storage feature through a work-in-progress branch. This implementation includes two new files - an Observable class and a Factory function. Observable class export class FirebaseUploadTaskObservable& ...

Exploring Angular 6 with Universal Karma for effective module testing

Issue I have been facing challenges while testing my Angular 6 application with Karma. I am encountering errors such as: Can't bind to 'ngModel' since it isn't a known property of 'mat-select'. Although the import works in ...

Managing multiple asynchronous requests through Observables in web development

I am working on an Angular2 website that sends multiple ajax requests using Json Web Tokens for authorization when it is initialized Here are two examples: public getUser(): Observable<User> { // Code block to get user data } public getFriends ...