so i have a object list for styles like this,
const styles = {
'font': 'font',
'fontSize': 'font-size',
'fontFamily': 'font-family',
'fontVariant': 'font-variant',
'fontWeight': 'font-weight',
'fontStyle': 'font-style',
'margin': 'margin',
};
<div style='MARGIN:10px; FLOAT:left'></div>
FYI-i'm using an editor so that when i paste the HTML code, sometimes it has those property names in UPPERCASE .
how to do i make sure that all the property names are lowercase what function/method should i use to check the case?
I think you need to combine what has been said already.
document.querySelectorAll('p').forEach(p => {
p.setAttribute('style', p.getAttribute('style').toLowerCase())
console.log(p)
})
<p style="COLOR: red;">Foo</p>
<p style="COLOR: blue;">Bar</p>
<p style="COLOR: green;">Baz</p>
That said, I wouldn't do it at runtime. Maybe do it once and serve the transformed HTML directly to the user. Maybe even some automated setup with gulp or 11ty.
The style are also visible without transforming. (for me in chrome)
If you can use ES6, then you could create a new object using Object.entries:
const lowerCaseStyles = Object.entries(styles).map(([key, value]) => ({ [key.toLowerCase()]: value}));
If im not wrong, you wanted to check if the properties of the style attribute are UPPERCASED or lowercased
First of all, you can first get the value of the style attibute like
const value = document.querySelector("div").getAttribute("style");
//this will return 'MARGIN:10px; FLOAT:left'
then you can simply turn them to lowercase with toLowerCase
const lowercased = value.toLowerCase();
and then you can check if the properties with something like
return value === lowercased
<div style='margin:10px; float:left'></div> returns true
<div style='MARGIN:10px; FLOAT:left'></div> returns false
Related
I have a nodelist with innerText. I am converting the innerText to an array.
Screen-shot of the nodelist:
Below is my code:
var fltarr = []
for( z=0; z<document.querySelectorAll("div.flight-number").length; z++){
fltarr.push(document.querySelectorAll("div.flight-number")[z].innerText)
}
Now I am creating the if conditions as below but instead of using or || statement, is there another way to use for example coma separated etc to keep the code cleaner and not to clutter with too many ||.
You can try with Array.prototype.some()
var flatarr= Array.from(document.querySelectorAll("div.flight-number")).map(el => el.textContent);
console.log(flatarr.some(i => ['NH 96', 'NH 98'].includes(i)))
// BY USING REGEX
console.log(flatarr.some(i => i.match(/^NH\s9[8|6]$/g)))
<div class="flight-number">NH 96</div>
<div class="flight-number">EY 871</div>
<div class="flight-number">NH 97</div>
For every match, try using Array.prototype.every()
You mean
[...document.querySelectorAll("div.flight-number")]
.filter(div => ["NH 98","NH 96"].includes(div.textContent.trim())
Easier to answer if you post actual HTML and what you want as output
Here are all the divs content
[...document.querySelectorAll("div.flight-number")]
.map(div => div.textContent.trim())
You can create an array of values you & use every to check if the values exist like this
var valuesToCheck = ['NH 96', 'NH 98']
flatarr.every(i => valuesToCheck.includes(i))
HTML
<div class="1"><div class="2">element1class2</div><div class="3">element1class3</div></div>
<div class="1"><div class="2">element2class2</div></div>
Javascript:
var class2List= document.querySelectorAll('div.class1 div.class2')
var class3List= document.querySelectorAll('div.class1 div.class3')
for (let i = 0; i < class2List.length; i++) {
nodes[i] = {
class2: class2List[i].innerText,
class3: class3list[i].innerText,
}
}
Hi, I'd like to know if it's possible to use querySelectors make an Array of HTML Elements in the following way:
i'd like an output array of of the the innerText, but when there is no class, to put an empty string.
[{class2: 'element1class2', class3: 'element1class3'},
{class2: 'element2class2', class3: ''} ]
right now, if there is no div class="3" in the node, then the NodeList length is reduce by 1 for every element not carrying a class="3" div.
The current output is innerText is not defined for class3list for class3List because the length of class3list is shorter than class2List.
Use optional chaining so that the value is undefined if the element doesn't exist, then use ?? to alternate with the empty string in such a case:
class3: class3list[i]?.innerText ?? '',
If you can't use optional chaining, you can use the conditional operator:
class3: class3list[i] ? class3list[i].innerText : '',
If you need to handle "holes" in the middle, then use a different approach: map the <div class="2" elements to their next sibling:
const nodes = [...document.querySelectorAll('[class="2"]')]
.map(class2 => ({
class2: class2.textContent,
class3: class2.nextElementSibling?.textContent ?? ''
}));
console.log(nodes);
<div class="1">
<div class="2">element1class2</div>
<div class="3">element1class3</div>
</div>
<div class="1">
<div class="2">element2class2</div>
</div>
Note that you need to use the [class="2"] selector string, not .class2, because your elements are not class="class2", but class="2".
You also need to fix the syntax of your HTML. The final
</div>/div>
should be
</div></div>
thanks to #certainperformance, I found a solution to my problem by taking the grouping selector (class1) and then mapping each array element with another querySelector for the class I'm looking for (class2 or class3)
for example:
const nodes = [...document.querySelectorAll('[class="2"]')]
thanks for the hint on the css selector for class=2
nodes.map(node => ({
class2: node.querySelector('[class="2"]') ? node.querySelector('[class="2"]').textContent: '',
class3: node.querySelector('[class="3"]') ? node.querySelector('[class="3"]').textContent: ''
}))
This way we can check if a class exists under the parent node for each parent in the nodeList.
I am working with react app in typescript. From API, I have this input:
a) list of variable names ["name", "surname"]
b) few strings in form of simple html with variables "<p>Hello, how are you {name}?</p>"
c) number of inputs with variables such as {input1: "name"}
everything as a string/JSON
what i need to do is: render simple html (only few tags) received from API but "create" binding between those dynamic inputs and variables in strings
in static world, result would look like:
[name, setName] = useState("")
<p>Hello, how are you {name}?</p>
<input type="text" onChange={e => setName(e.target.value)}/>
However, all of this is dynamic. String "<p>Hello, how are you {name}?</p>" doesnt get binded to the input on its own.
I tried:
setting variable [vars, setVars] = useState({}), property for each dynamic variable, with
a) dangerouslySetInnerHTML - renders only html (cannot bind the variable inside to the input)
b) react-html-parser - same as above
c) babel.transform - couldnt make it work as this is done dynamically and in browser, it cannot find the right preset, i couldnt make the mimified babel.js work with typescript How to render a string with JSX in React
do you see some easy way? For example how could i use React.createElement to render html with "live" variable inside, represented as {variableName}? Or maybe something out of the box? giving each elemnt a class and finding the class in DOM and editing the text with input change would be probably very non-optimal?
I hope this could be a better example:
{response:
{
variables: ["name", "name2", "mood"],
texts: [
"<em> Hello! My name is {name}</em>",
"<p> Hi {name} ! I am <strong>{name2}</strong> and I feel {mood} today</p>"
],
inputs: [
{
label: "How do i feel?"
input: {mood}
}
]
}
}
EDIT:
This should give you a good idea:
https://stackblitz.com/edit/react-ts-cwm9ay?file=DynamicComponent.tsx
EDIT #2:
I'm pretty good with React and interpolation, it's still in progress (specifically the docs, but the readme is complete) but I'm going to shamelessly plug my ReactAST library
EDIT #3 - If you're interested in doing crazy dynamic interpolation, then you might also want to check out a neat dynamic interpolation (and it's reverse) library
Let's assume this:
{
vars: ['name','surname'],
strings: ["<p>Hello, how are you {name}?</p>","<p> It's night to meet you {name} {surname}"],
inputs: {
input1: 'name',
input2: 'surname'
}
}
Create a component (or set of components) that can do this.
I haven't even ran any of this, but here's the idea. I'll put it in a stackblitz in a bit and polish it up to make sure it works:
const MyDynamicComponent = ({vars,strings,inputs}) => {
const [state,setState] = useState(vars.reduce((acc,var) => ({...acc,[var]:undefined}));
return (
<>
<MyDynamicText vars={vars} strings={strings} state={state}/>
<MyDynamicInputs onChange={(name,val) => setState({[name]:val}) state={state} inputs={inputs}/>
</>
)
}
const MyDynamicText = ({vars,strings,state}) => {
return strings.map((s,i) => s.replaceAll(`{${vars[i]}}`,state[vars[i]])
}
const MyDynamicInputs = ({onChange,inputs,state}) => {
return Object.entries(inputs).map(([inputName,varName]) => <input key={inputName} onChange={e => onChange(varName,e.target.value)} value={state[varName]}/>
}
I cant seem to figure this one out I am trying to check if an input is inlcuded in an array of nodes. No matter what I try it seems to return false. I'm thinking it must be something simple that I'm missing.
Here is what I have
const error = document.getElementsByClassName('has-form-error')
let focusedInputNodeList = error[0].childNodes
let focusedInput = Array.from(focusedInputNodeList)
This is to check for the most immediate form error. I then want to check the return if it is an input, textarea, or select.
the above code returns the array to console from my html
(6) [text, label, text, div.form-error, input#first_name, text]
Then I try
console.log(focusedInput.includes('input')) //returns false
I figured maybe it was due to the #first_name so I tried using
console.log(focusedInput.includes('text')) //returns false
and
console.log(focusedInput.includes('#text')) //returns false
None of these attempts seemed to work. My goal is to eventually have something that looks like
if (focusedInput.includes('input')) {
focusedInput[4].focus() //even better if I could find a way to select focusedInput.input.focus()
}
if (focusedInput.includes('textarea')) {
focusedInput[5].focus() // even better if I could find a way to select focusedInput.textarea.focus()
}
The problem is that your array focusedInput contains elements and not strings. In the code below I get an additional array of the element types, as strings, and from that you can find what you want.
The other thing I did was to use .children to get all of the non-text elements to reduce what is in the array.
const error = document.querySelector('.has-form-error');
let focusedInputNodeList = error.children;
let focusedInput = Array.from(focusedInputNodeList);
let nodeTypes = focusedInput.map(el=>el.localName);
console.log(focusedInput);
console.log(nodeTypes.indexOf('label'));
console.log(nodeTypes.indexOf('input'));
<div class="has-form-error">
<label>Click me</label>
<div class="form-error">Error</div><input id="first_name" />
</div>
UPDATE
In a comment you said: "even better if I could find a way to select focusedInput.input.focus()"
So why not do this:
const input = document.querySelector('.has-form-error input');
if (input) {
input.focus();
}
<div class="has-form-error">
<label>Click me</label>
<div class="form-error">Error</div><input id="first_name" />
</div>
You cannot just check for includes like that, since it's not an array of strings ['text', 'input', 'etc']. It's an array of node objects, and the name you're looking for is a property of that node, which you can find like focusedInput[5].localName (or .tagName or .nodeName).
So, like:
focusedInput.forEach(item => {
if (item.localName === 'input') {
item.focus()
}
})
I've searched for this particular topic and couldn't find anything similar to it. If there is please close this and give a link.
I'm creating a json data api simulator. I want users to be able to copy and paste a json object request into a textarea where they can also modify it before sending it to the server.
Problem is json obj copy and patses often results in extra spaces and is never aligned properly, even with the pre tag. I also want a good color scheme applied to keys and values.
I've seen plugins, other questions and snippets of code, but they don't apply to textareas where the text is editable. Is there to keep it styled while in edit mode without it showing all the html tags that styled it? I want to be able to write it from scratch with javascript or jquery.
The syntax highlighting is tough but check out this fiddle for pretty printing a json object entered in a text area. Do note that the JSON has to be valid for this to work. (Use the dev console to catch errors.) Check jsLint for valid json.
The HTML:
<textarea id="myTextArea" cols=50 rows=10></textarea>
<button onclick="prettyPrint()">Pretty Print</button>
The js:
function prettyPrint() {
var ugly = document.getElementById('myTextArea').value;
var obj = JSON.parse(ugly);
var pretty = JSON.stringify(obj, undefined, 4);
document.getElementById('myTextArea').value = pretty;
}
First try simple input like: {"a":"hello","b":123}
Simple pretty printing of JSON can be done rather easily. Try this js code: (jsFiddle here)
// arbitrary js object:
var myJsObj = {a:'foo', 'b':'bar', c:[false,2,null, 'null']};
// using JSON.stringify pretty print capability:
var str = JSON.stringify(myJsObj, undefined, 4);
// display pretty printed object in text area:
document.getElementById('myTextArea').innerHTML = str;
For this HTML:
<textarea id="myTextArea" cols=50 rows=25></textarea>
And check out JSON.stringify documentation.
Late answer but modern one, use the secret intendation parameter.
I usually go for:
JSON.stringify(myData, null, 4);
Here's the code definition, it explains it well.
stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;
/**
* Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
* #param value A JavaScript value, usually an object or array, to be converted.
* #param replacer An array of strings and numbers that acts as a approved list for selecting the object properties that will be stringified.
* #param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
*/
For the parsing step you're just going to want to JSON.parse the contents of the textarea and handle any errors from bad input.
For the formatting part of your question, Use JSON.stringify(blob, undefined, 2). Alternatively, if you need colors here is a simple JSON format/color component written in React:
const HighlightedJSON = ({ json }: Object) => {
const highlightedJSON = jsonObj =>
Object.keys(jsonObj).map(key => {
const value = jsonObj[key];
let valueType = typeof value;
const isSimpleValue =
["string", "number", "boolean"].includes(valueType) || !value;
if (isSimpleValue && valueType === "object") {
valueType = "null";
}
return (
<div key={key} className="line">
<span className="key">{key}:</span>
{isSimpleValue ? (
<span className={valueType}>{`${value}`}</span>
) : (
highlightedJSON(value)
)}
</div>
);
});
return <div className="json">{highlightedJSON(json)}</div>;
};
See it working in this CodePen:
https://codepen.io/benshope/pen/BxVpjo
Hope that helps!
If you are a jquery fan, you can also use this small plugin I wrote:
// The plugin
$.fn.json_beautify= function() {
this.each(function(){
var el = $(this),
obj = JSON.parse(el.val()),
pretty = JSON.stringify(obj, undefined, 4);
el.val(pretty);
});
};
// Then use it like this on any textarea
$('textarea').json_beautify();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<textarea id="myTextArea" cols=50 rows=5>{"name":"John","age":30}</textarea>
<textarea id="myTextArea2" cols=50 rows=5>{"name":"Bob","age":55}</textarea>
UPD
Changed code to multiselected elements.
I don't think that can be done with regular textareas. What you can do (and how most online code editors do it) is to create a transparent textarea that overlays on top of a div that contains the styled code. The user would still be able to type and interact with the input (and it fires the associated form events), and you can show syntax highlighting in the div that the user will visually see
(see Textarea that can do syntax highlighting on the fly?)
Now as for JSON formatting, I would add custom events to the textarea so that when a user types or paste something, run it through a Javascript JSON prettifier (see How can I pretty-print JSON using JavaScript?) and then re-populate the div and textarea accordingly
Here's a recursive function to return an object if it has been stringified multiple times:
const jsonPrettify = (json) => {
if (typeof json === 'object' && json !== null) {
const pretty = JSON.stringify(json, undefined, 4);
return pretty;
}
try {
const obj = JSON.parse(json);
return jsonPrettify(obj);
} catch (e) {
return json;
}
};