Convert into HTML checkboxes using JSON values in react - javascript

This JSON is dynamic, coming from API and I can't change it. I want to get table.cc value and convert it into HTML checkbox.
let table = {
id: 1,
value: "abc",
height: 1080,
width: 1920,
cc: "{"c08":false,"c07":true}"
}
let headers = Object.keys(table);
let rows = Object.values(table);
let cc = table.cc ? JSON.parse(table.cc) : null;
if(cc) {
let output = Object.entries(cc).map(([key, value]) => {
return `<input type="checkbox" checked=${value}>
<label>${key}</label>`;
}).join('');
console.log(output);
rows[4] = `${output}`; // I am getting a string. I am unable to convert it into HTML markup.
}
Since I am looping over Object.values(table), I want to change only the table.cc to get HTML checkboxes. So, in the case of the above example table.cc should have 2 checkboxes in HTML and the second one should be checked since the value is true. The label should be the key.
Any ideas?
I have put a link in stackblitz to edit the code.
https://stackblitz.com/edit/react-5dtdjt

Your code is working after some fixes. You should not add html tags as strings in JSX. And a Fragment needs to be used as parent element.
import React, { Component, Fragment } from 'react';
--------
...
if (cc) {
let output = Object.entries(cc).map(([key, value]) => {
return (
<Fragment>
<input type="checkbox" checked={value} />
<label>{key}</label>
</Fragment>
)
});
rows[4] = output

Related

ng-select not displaying search values properly after pasting in values

When trying to update array of strings acting as the model for ng-select, the values do not display properly in the search box itself.
the values that are showing up properly, are the ones that are selected from the dropdown, the ones that do not display properly are numbers I am trying to add on to the list manually
select box in template:
<ng-select
id="oNumberSelect"
[items]="ownerNumberResults | async"
[typeahead]="typeAhead$"
bindLabel="desc"
bindValue="code"
dropdownPosition="bottom"
[(ngModel)]="selectedOwnerNumbers"
(ngModelChange)="handleSelectionChange()"
[multiple]="true"
[searchable]="true"
multiple="true"
style="overflow-y: auto; width: 100%"
appendTo="body"
(paste)="handlePaste($event)"
minTermLength="3"
[addTag]="true"
>
</ng-select>
methods referenced:
handlePaste(pasteEvent: ClipboardEvent): void {
pasteEvent.stopPropagation();
pasteEvent.preventDefault();
const clipStrings:string[] = [...pasteEvent.clipboardData.getData('Text').trim().split(/[\s,)]+/)]
this.selectedOwnerNumbers = [...this.selectedOwnerNumbers, ...clipStrings];
}
searchOwnerNumbers(): void {
this.ownerNumberResults = this.typeAhead$.pipe(
distinctUntilChanged(),
debounceTime(500),
switchMap(term => {
return this.ownerHttpService.searchOwnerProperty('ownerNumber', term);
}
)
);
}
handleSelectionChange(): void {
console.log(this.selectedOwnerNumbers)
}
select variables:
selectedOwnerNumbers: string[];
typeAhead$ = new Subject<string>();
ownerNumberResults: Observable<Option[]>;
I have tried using sets, arranging arrays differently, concatenating the pasted values, but i cant get them to show up in the UI correctly
this usually happens if the bindValue and bindLabel are different.
try changing the handle paste logic like this
handlePaste(pasteEvent: ClipboardEvent) {
pasteEvent.stopPropagation();
pasteEvent.preventDefault();
const clipStrings: string[] = [
...pasteEvent.clipboardData
.getData('Text')
.trim()
.split(/[\s,)]+/),
];
this.selectedOwnerNumbers.push(this.ownerNumberResults.find(result => result.desc === clipStrings[0]).code);
this.selectedOwnerNumbers = [...this.selectedOwnerNumbers]
}

Render HTML tag from Json response to template literals

I am getting data from an API using Fetch with HTML tag in the JSON responses but after I render it on a page using template literals the tags are removed and the response is displayed in plain text.
Example JSON from the API:
"value" : {
"key":"something < strong >keyword < /strong >"
}
This is my fetch request and render:
fetch('www.someurltogetdata').then(response => { if (! response.ok) {
var counter = '< div>< h3 >Something went wrong, please try again</h3></div>';
throw Error("Error") }
return response.json(); }).then(data => {
var html = data.value.map(data => {
return `< div class="result">
<a href=${data.url}>${data.content}</a></div >`
}).join('')
//to render the HTML
document.querySelector('.someclass').insertAdjacentHTML('afterbegin', html)
Desired result:
something keyword
but it's not working. The JSON value is rendered as plain text without tag like this: something keyword
Please help me render json value with HTML tag?
Create a new document fragment with createRange and createContextualFragment, and then append that to an existing element.
const value = {
key: 'something <strong>keyword</strong>'
};
let range = document.createRange()
const frag = range.createContextualFragment(value.key);
const div = document.querySelector('div');
div.appendChild(frag);
<div />

Saving Values to Backend from TextBoxes using React Flux Pattern

I have several text boxes and a save button
Each text box value is loaded using the following approach
{
this.getElement('test3lowerrangethreshold', 'iaSampling.iaGlobalConfiguration.test3lowerrangethreshold',
enums.IASamplingGlobalParameters.ModerationTest3LowerThreshold)
}
private getElement(elementid: string, label: string, globalparameter: enums.IASamplingGlobalParameters): JSX.Element {
let globalParameterElement =
<div className='row setting-field-row' id={elementid}><
span className='label'>{localeHelper.translate(label)}</span>
<div className="input-wrapper small">
<input className='input-field' placeholder='text' value={this.globalparameterhelper.getDataCellContent(globalparameter, this.state.globalParameterData)} />
</div>
</div>;
return globalParameterElement;
}
Helper Class
class IAGlobalParametesrHelper {
public getDataCellContent = (globalparameter: enums.IASamplingGlobalParameters, configdata: Immutable.List<ConfigurationConstant>) => {
return configdata?.find(x => x.key === globalparameter)?.value;
}
}
This works fine. Now the user is allowed to update these text values.And on click of save the changes should be reflected by calling a web api .
I have added an onlick event like this
<a href='#' className='button primary default-size' onClick={this.saveGlobalParameterData}>Save</a>
Now inorder to save the data i need a way to identify the text element which has changed.For that i have added an update method within the Helper class
public updateCellValue = (globalparameter: enums.IASamplingGlobalParameters, configdata: Immutable.List<ConfigurationConstant>,updatedvalue:string) => {
let itemIndex = configdata.findIndex(x => x.key === globalparameter);
configdata[itemIndex] = updatedvalue;
return configdata;
}
and return the updated configdata ,and i plan to call this method in the onchange event of every text box like this
<input className='input-field' placeholder='text' onchange={this.setState({ globalParameterData: this.globalparameterhelper.updateCellValue(globalparameter, this.state.globalParameterData, (document.getElementById(elementid) as HTMLInputElement).value})}
But this does not seem like a correct approach as there are number of syntactical errors. I initially got the data using an actioncreator like this.Please advice.
samplingModerationActionCreator.getGlobalParameters();
samplingModerationStore.instance.addListener(samplingModerationStore.SamplingModerationStore
.IA_GLOBAL_PARAMETER_DATA_GET_EVENT,
this.getGlobalParameterData);
}

Svelte each block rendering only the last item

I'm trying to make a tag input component in svelte and I've encountered a strange #each block behavior. I have the following svelte code
<script>
import Input from './Input.svelte'
import Tag from './Tag.svelte'
export let tagValues = []
let currentTag = ''
function handleEnter({ key }) {
if (key === 'Enter' && currentTag) {
if (tagValues.indexOf(currentTag) < 0) {
tagValues = [...tagValues, currentTag]
}
currentTag = ''
}
}
</script>
<div class="relative">
<Input bind:value={currentTag} on:keyup={handleEnter}></Input>
{#each tagValues as t (t)}
<Tag value={t}></Tag>
{/each}
{JSON.stringify(tagValues, null, 2)}
</div>
The idea is to get the input value when the user hits Enter key and add that value as a tag if it isn't present already. Input component behaves the same as input Html element. Tag component only has a value property which is text, this should render all the values of the tagValues array, but only shows the last one. I can confirm that the array includes correctly new tags, because I pasted a stringify version of it to HTML. This is how it looks with 1 tag
And this is with two tags
How can I make this component to render all tags? I have tried to make my each block keyed but nothing changed.

JavaScript - Having trouble splicing an item from an array and then re-rendering that array to my page

Essentially, I'm rendering a couple of notes from a notes[] array to my page and adding a button to each note that, when clicked, will remove the note from the array using splice(), then re-render the remaining notes. The button is given an id based on the title of the note (given as input by a user), which is also given a similar id.
This is just some Vanilla JS for a personal project and after looking around this morning I've yet to find a solution that doesn't deal with Vue, Angular, or some other framework/package.
HTML
This is the relevant HTML:
<main>
<div id="container">
<form id="utilities">
<input type="text" name="userTitle" id="user-title" placeholder="Title" autocomplete="off">
<input type="text" name="userBody" id="user-body" placeholder="Body" autocomplete="off">
<div id="buttons">
<input type="submit" name="userSubmit" id="user-submit" value="Submit">
</div>
<input type="text" name="userFilter" id="user-filter" placeholder="Search" autocomplete="off">
</form>
<div id="results"></div>
</div>
</main>
JavaScript
The following JS snippets are all in order, simply broken up for readability and comments.
This is the array I'm passing to and pulling from. It takes a title, a body, an id.
const notes = [{
title: 'Grocery List',
body: 'Buy milk, eggs, and bread',
id: 'grocery-list'
},
{
title: 'Workout Routine',
body: 'running, push-ups, rowing',
id: 'workout-routine'
}
]
This is my function that's getting the title and body text from the user input. It is called in renderNotes().
const results = document.querySelector('#results');
const createElement = function(noteTitle, noteBody) {
const newNote = document.createElement('div');
const newTitle = document.createElement('h3');
const newBody = document.createElement('p');
const newButton = document.createElement('div');
newTitle.textContent = noteTitle;
newTitle.classname = 'note-title';
newBody.textContent = noteBody;
newBody.className = 'note-body';
newButton.className = 'note-button';
newButton.innerHTML = '⮿';
newButton.id = `button-${newTitle.textContent.toLowerCase()}`.replace(' ', '-');
newNote.appendChild(newTitle);
newNote.appendChild(newButton);
newNote.appendChild(newBody);
newNote.className = "note";
newNote.id = newTitle.textContent.toLowerCase().replace(' ', '-');
results.appendChild(newNote);
}
renderNotes() is simply calling createElement() on each note in that array. Then I'm calling it for the first time.
const renderNotes = function(list) {
console.log(list)
list.forEach(function(item) {
createElement(item.title, item.body)
})
}
renderNotes(notes);
This snippet seems to be where I'm failing. It should be getting each button (created during the createElement() calls) and adding an eventListener('click') to it. Then it is supposed to look through each of the notes in notes[], find the one which has a similar id to that of the button pressed, and splice() that note from the notes[] array. Then I simply want to re-render the notes.
document.querySelectorAll('.note-button').forEach(function(button) {
button.addEventListener('click', function(e) {
notes.forEach(function(note) {
if (e.target.id.includes(note.id)) {
notes.splice(notes.indexOf(note), 1)
}
renderNotes(notes)
})
})
});
Actual Results
The notes seem to be spliced from the array consistently, but my problem lies in getting them to re-render. Currently it's just removing the items and then either failing to render or is adding more copies to the page. Edit to add: I'm not receiving any errors in the console, the code is just executing properly as far as the computer is concerned. So I know it's definitely a "Problem Between Chair and Keyboard" error.
Hopefully this makes sense. I appreciate any responses.
You're calling renderNotes(notes) at each iteration not only after the array was mutated.
Try something like:
const clickedNote = notes.find(note => e.target.id.includes(note.id));
notes.splice(notes.indexOf(clickedNote), 1);
renderNotes(notes);
A better solution will be to define notes using let and then do something like this:
notes = notes.filter(note => !e.target.id.includes(note.id));
renderNotes(notes);

Categories