I have this functionality for highlighting certain characters in the HTML of my component:
highlightQuery() {
// will output the text response from the Model, but also highlight relevant words if they match the search query
// that the user input
let input = this.props.model.get('value');
if(!this.state.hasMatch){
return input;
}
let query = this.props.matched.query,
index = this.props.model.get('searchIndexes')[this.props.matched.index];
const replaceBetween = (str, start, end, what) => {
return str.substring(0, start) + what + str.substring(start + end);
};
let ret = replaceBetween(input, index, query.length, `<span class='highlighted'>${query}</span>`);
return ret;
},
render() {
return (
<span dangerouslySetInnerHTML={ {__html: this.highlightQuery()} }></span>
);
}
So as you can see, if there's no match in this component's value then just return the input contents, else, wrap the matched text in a <span />.
What I'm after, is to avoid using dangerouslySetInnerHTML. Is this possible?
I'm not sure this will perfectly answer your question but I would do this to avoid dangerouslySetInnerHTML.
render() {
highlightQuery() {
let input = this.props.model.get('value');
if(!this.state.hasMatch){
return input;
}
let query = this.props.matched.query,
index = this.props.model.get('searchIndexes')[this.props.matched.index];
const replaceBetween = (str, start, end, what) => {
return str.substring(0, start) + what + str.substring(start + end);
};
let ret = replaceBetween(input, index, query.length, `<span class='highlighted'>${query}</span>`);
return ret;
}
var mycontent = highlightQuery();
return (
<span> {mycontent} </span>
);
}
hope it helps
Edit: I think I understand what you've meant now but in my opinion it doens't change the strategy, you work inside the render, choose your content and render it. (or maybe I still don't get it.. =p)
Is there any reason highlightQuery cannot return a react element?
highlightQuery(input,query, index) {
// will output the text response from the Model, but also highlight relevant words if they match the search query
// that the user input
var before = input.substring(0, index);
var after = input.substring(index + query.length);
return <span>{before}<span class='highlighted'>{query}</span>{after}</span>;
},
render() {
var input = this.props.model.get('value');
var query = this.props.matched.query;
var index = this.props.model.get('searchIndexes')[this.props.matched.index];
if(!this.state.hasMatch){
return <span>{input}</span>;
} else {
return highlightQuery(input, query, index);
}
}
Related
There is a React component -
'function Product (props) {
const {
prod_id: id,
prod_name : title,
prod_status: status,
prod_price: price,
prod_oldprice : oldPrice,
} = props;
let oldPriceChecker = (oldPriceValue) => {
if (oldPriceValue) {
let oldPriceStr = oldPriceValue + ' zł';
return(oldPriceStr);
}else {
return('');
}
}
let statusChecker = (value) => {
if (value != undefined){
let string = value;
let array = string.split(',');
console.log(array);
array.map(n => <div className="status">{n}</div>)
}
}
return (
<div className="row">
<div className="card">
<div className="card-image">
<img src="https://via.placeholder.com/150" />
</div>
<div className="card-content">
<span className="card-title">{title}</span>
<hr className="card_hr" />
<p className="card_price" >{price} zł</p>
<div className="card_price old_price">{oldPriceChecker(oldPrice)}</div>
{statusChecker(status)}
</div>
</div>
)
}
export {Product}
Question: The variable prod_status: status can contain several values (for example, "new,promotion", if so, you need to split it into two words and create a separate block for each, since now the block comes with the whole line
It is necessary like this (new, saleout, etc. in separate blocks)
I tried to create a function but it just outputs an array to the console
I think I'm not using the property "map" correctly
The problem:
The function you have created statusChecker does not return anything. Therefore when you want to print it ({statusChecker(status)}) it doesn't do anything.
let statusChecker = (value) => {
if (value != undefined){
let string = value;
let array = string.split(',');
console.log(array);
//This is what you want to return but is not returned
array.map(n => <div className="status">{n}</div>)
}
}
Solution:
return the mapped array from the function.
let statusChecker = (value) => {
if (value != undefined){
let string = value;
let array = string.split(',');
console.log(array);
//This is what you want to return but is not returned
return array.map(n => <div className="status">{n}</div>)
}
}
The main problem with your code is that you are trying to create an html element just by writing it, and that is not possible. The closest thing to that is for you to use innerHTML. for example: parent.innerHTML = <div className="status">${n}</div>. being "parent" an html element previously created (document.createEement()) or already existing in the DOM.
In my solution I used document.createElement() to create a div and insert the text into it. The function returns an array with the div elements and their respective words inside but only that, it doesn't print anything on the screen. If all you want is to display it on the screen the process is a bit different.
let statusChecker = (value) => {
// Instead of doing " if (value != undefined) I used
let nodes = value?.split(',').map(n => {
// first you have to create an element
let div = document.createElement('div')
// add the class status
div.classList.add('status')
// insert each word into the div
div.textContent = n;
return div
})
return nodes
}
console.log(statusChecker('new,promotion'))
Here is my current script and attached sheet.
I have been able to successfully find the index value with function getColumnIndex(label) and then return that function into function getColumnValues(index) to pull all the rows in that specific column. I can't seem to use the input field from the autocomplete question id="courseCode" Enter Course Code as the search string to be used in the function getExpectations(); to populate the HTML page question id="expectations" as a multi selection question.
It works if I manually add the search string text to return the column rows. I would like to take the first 4 characters of the input field id="courseCode" Enter Course Code (3 letter followed by a number) as the search string to determine what selection options will populate the id="expectations" question.
I am a bit confused with calling back functions within another function and when and how to use a parameter/condition to pass through the function.
I hope this is enough information to solve my script error. Thanks in advance for this concern. Take care.
Added the following lines of code to get all options selected in the multi-selection Course Expectations question.
function collectForm(){
var submission = {};
// gets you the values for all id="specific_names"
submission.grade = document.getElementById("grade").value;
submission.courseCode = document.getElementById("courseCode").value;
var list = document.getElementsByClassName('selectedExpectations');
var selection = ' ';
for (i = 0; i < list.length; i++){
if (list[i].checked === true) {
selection += list[i].value + ", ";
}
}
submission.expectations = selection;
google.script.run.userClicked(submission);
}
In short
You need something like this
/**
*
* #param {string} code
*/
function getExpectations2(code) {
var patt = new RegExp(code.slice(0, 5), 'i');
var data = SpreadsheetApp.openById(
'1evNXXgFITrdNwsSdGXmprgzti74AQy03dg0igP5nT0I'
)
.getSheetByName('expectations')
.getDataRange()
.getValues();
var colIndex = data[0].reduce(function(p, c, i) {
return patt.test(c) ? i : p;
}, -1);
return colIndex === -1
? []
: data
.slice(1)
.filter(function(row) {
return row[colIndex] !== '';
})
.map(function(row) {
return row[colIndex];
});
}
getExpectations2 - returns a column by code as a list.
Also you have to update your listExpectations
function listExpectations(listLabels) {
console.log(listLabels);
const elm = document.getElementById('expectations');
const label = listLabels
.map(row => `<option value="${row}">${row}</option>`)
.join('');
elm.innerHTML =
'<option disabled selected>Select expectations not met</option>' + label;
setTimeout(() => M.FormSelect.init(elm), 0);
}
Of course you need bind all of them
function populateCodes(codes) {
var autocomplete = document.getElementById('courseCode');
var instances = M.Autocomplete.init(autocomplete, {
data: codes,
onAutocomplete: onAutocompleteCourseCode,
});
}
Where onAutocompleteCourseCode is
const onAutocompleteCourseCode = courseCode => {
google.script.run
.withSuccessHandler(listExpectations)
.getExpectations2(courseCode);
};
I have the multiple line string which need to remove/add
here's the data that I would like to edit
data{
id
date
***progress{
update
progressStatus
}***
events {
id
time
}
}
my point is how do I remove
progress{
update
progressStatus
}
I had tried 'replace', 'assign' to remove it as below but not working
const test = data.replace(progress, '');
Thank you.
Here's the logic, I'm considering that you want to remove the "progress" which has an open curly bracket('{') and a closing curly bracket('}'):
var data = `data{
id
date
***progress{
update
progressStatus
}***
events {
id
time
}
}`;
function _remove(data, key) {
var s = data.indexOf(key);
var e = ((s) => {
for(var i=s; i<data.length; i++){
if(data[i] == "}")
return i;
}
})(s + key.length);
console.log(data.replace(data.substr(s, e-s+1), ""));
}
_remove(data, 'progress');
Can be done with regex as well!
What is I have the multiple line ? The query of grapqh will return an object, why still a multiple string ?
In your case (the query data is a string), try:
const data = ` data{
id
date
progress{
update
progressStatus
}
events {
id
time
}
}`
const newData = data.replace(`progress{
update
progressStatus
}`, '')
console.log(newData)
If you want to delete one key in object, try this:
delete data.progress;
// or,
delete data['progress'];
// or,
const prop = "progress";
delete data[prop];
Demo:
const data = {
progress: {
x: "x"
},
events: {
id: 1
}
}
delete data.progress
console.log(data)
You could try with a regexep
const regex = /progress{[^}]+}\s+/gm;
const str = `data{
id
date
progress{
update
progressStatus
}
events {
id
time
}
}`;
const subst = ``;
// The substituted value will be contained in the result variable
const result = str.replace(regex, subst);
console.log('Substitution result: ', result);
I'm trying to make a function which replaces specific strings within a set of code according to a pre defined list of search words and what it should be replaced with,
render = (data,list) => {
let temp = data;
for(let i in list){
temp.split(i).join(list[i]);
//temp.replace(new RegExp(i, 'g'), list[i]); even this doesn't work
}
return temp;
}
let test = render("<h1>a1</h1>",
{ "a1" : "Hello World" });
I don't see any errors, it just doesn't replace anything and returns the original data as it is, if I use the code used for the replacement separately and manually place in the values in the regExp or split join functions, it works fine..
//edit
The Expected input and output should be,
let temp = "<h1> $1 </h1>";
console.log( render(test, { "$1":"Hello World" } ) );
This is supposed to output,
<h1> Hello World </h1>
but I instead get
<h1> $1 </h1>
as it is.
Here's solution -
render = (data, list) => {
let temp = data;
for (let i in list) {
temp = temp.replace(new RegExp(i, 'g'), list[i]);
}
return temp;
}
let test = render("<h1>a1</h1>", {
"a1": "Hello World"
});
console.log(test);
I'm getting json data with a bunch of spaces as strings like this:
{
appNumber: " "
}
but at times i get this back
{
appNumber: "123456"
}
I want to be able to detect when it doesnt have any numerical value in it and display a dash instead
so in my controller i have:
$scope.appNumber = function() {
var appNumber = $scope.appNumber.trim();
if (!appNumber) {
return "-";
}
return $scope.appNumber;
};
in my HTML:
<div ng-bind="appNumber()"></div>
You are calling trim on the current scope function. change the name of your variable you want to trim
To return appNumber if it is a number or '-' try below
$scope.appNumber = function() {
$scope.str = "12312";
var x = + $scope.str;
if (x.toString() === $scope.str) {
return $scope.str;
}
return '-';
};
Working fiddle