Imagine the following scenario: I have this HTML body (this is just one example, the delimiters will be configurable by 3rd parties, so no way to use DOM methods like getElementBy...) :
<div id="login">
<form method="post" action="https://site.com/login.html?skin=webmail" id="fWM">
<fieldset>
<p><label>Login<br><input type="text" class="inpText" name="user" id="user"/> </label><span class="provider">#isp.com</span></p>
<p><label>Password<br><input type="password" class="inpText inpPass" name="pass" id="pass"/></label></p>
</fieldset>
<p id="forgot">
Forgot password? <span class="pipe">|</span>
Help
</p>
<br><a><input type="submit" value="" id="bOK"/></a></p>
</form>
Ok, this is just a part of some html body asking for Login and Password. As you can see, I have
< fieldset > and < /fieldset > and for this example those are my delimiters. This mean, everything between this delimiters I want to change for another html code. I have some 'begin of code' like this to you have some idea about what I'm talking:
var myBody = document.body.innerHTML;
var beginInject = myBody.indexOf("<fieldset>");
var endInject = myBody.indexOf("</fieldset>");
var InjectBody = 'Hello World!';
//what to do now to put Hello World! between the <fieldset> and </fieldset>??
Remember this is just one example, I can need to put the delimiters like < body> and < /body> or something like: "Click Here to Start download" and "Thank you for visiting this website"... What I mean is: can be anything inside the body, and between the 2 delimiters I want to put my HTML code. Thank you.
If you insist to make it your way, use
var beginText = "<p>",
endText = "</p>",
injectText = 'Hello World!';
var html = document.body.innerHTML,
beginPos = html.indexOf(beginText),
endPos = html.indexOf(endText);
document.body.innerHTML =
html.substring(0, beginPos + beginText.length)
+injectText
+html.substring(endPos + endText.length);
Demo
But be aware that this way
You will remove all event listeners inside your body
You will lose all element's properties (not attributes)
Browser will reload all body (slow)
And it won't work on all cases. For example:
If you search for <p>, you won't match <p class="myClass">
If you search for <p a="b" c="d">, you won't match <p c="d" a="b">
Text could be matched instead of real elements, for example if text appears in a textarea.
endPos could be smaller than beginPos, for example because it appears in a textarea.
The problem is that You can't parse [X]HTML with regex because Zalgo is coming, so it's even worse to parse it with just text.
You could use document.querySelector.
For example:
document.querySelector('#login fieldset');
And its argument can be the selector that you want. This way you don't have to worry if you are matching by id, by class, by tagname, by name, etc.
Related
Using plain vanilla JS is there a way of being able to change the text content that appears beside a checkbox when that input is nested within a label tag? Specifically adding a HTML link to the text?
I can change the text no problem but setting the content to display HTML just ends up rendering the HTML to screen. So, in the following example I want to make the Terms and Conditions text a link.
<label for="custom_field">
<input type="checkbox" name="custom_field" id="custom_field" value="I have read the terms and conditions"> I have read the terms and conditions
</label>
I've been through using nodes and siblings and while I can change the text either one of two things happen - I either end up overwriting all the content between the label tags and therefore killing the checkbox.
Or my anchor tag gets rendered to screen instead of interpreted.
Any ideas where I'm going wrong?
Here's the latest code I'm trying:
let terms = document.querySelector('#custom_field');
if(terms){
terms.nextSibling.innerHTML = "I have read and agree to the <a href='#'>terms and conditions</a>";
}
NOTE: Due to restrictions in my CMS I can't edit the content of the label directly to just insert the relevant HTML. So what I need to work with is as per the first code block.
innerHTML doesn't work because terms.nextSibling is a Text node, which doesn't have an innerHTML property.
You'll need to split the label's Text node on "terms and conditions", then move that node into a link:
const terms = document.querySelector('#custom_field');
if (terms) {
const fullText = terms.nextSibling;
const link = document.createElement('a');
link.href = '#';
const tcIndex = fullText.textContent.indexOf('terms and conditions');
const termsText = fullText.splitText(tcIndex);
// If there's more text after "terms and conditions", you'll need to split again
// termsText.splitText('terms and conditions'.length);
fullText.parentElement.insertBefore(link, termsText);
link.append(termsText);
}
<label for="custom_field">
<input type="checkbox" name="custom_field" id="custom_field" value="I have read the terms and conditions"> I have read the terms and conditions
</label>
Why not add an extra HTML tag?
<label for="custom_field">
<input type="checkbox" name="custom_field" id="custom_field">
// Added Span
<span id="result"> I have read the terms and conditions</span>
</label>
<script>
let terms = document.querySelector('#custom_field');
if(terms){
document.getElementById('result').innerHTML = "I have read and agree to the <a href='#'>terms and conditions</a>";
}
</script>
I believe that this is the most basic way to do it using plain JavaScript. Since you have a text node after your checkbox, you'll need to first find the text you want to replace, and then replace it with your HTML that is wrapped in a new node that can contain HTML (the existing text node can't be converted).
let terms = document.querySelector('label');
for (var i = 0; i < terms.childNodes.length; i++) {
var textNodeTrimmed;
if (terms.childNodes[i].nodeType === 3) textNodeTrimmed = terms.childNodes[i].nodeValue.trim()
if (textNodeTrimmed.length > 0 && textNodeTrimmed === "I have read the terms and conditions") {
var replacementNode = document.createElement('span');
replacementNode.innerHTML = "I have read and agree to the <a href='#'>terms and conditions</a>";
terms.childNodes[i].parentNode.insertBefore(replacementNode, terms.childNodes[i].nextSibling);
terms.childNodes[i].remove();
}
}
<label for="custom_field">
<input type="checkbox" name="custom_field" id="custom_field" value="I have read the terms and conditions"> I have read the terms and conditions
</label>
Full Working Example
you can add the value by plain js using parentnode
then replacing the old text by cutting the checkbox using children[0].outerHTML and pasting it again with the new content
that new content can include HTML anchors or any other tags
I am a total noob to javascript and need some direction.
I am trying to do the following:
Create 3 text boxes:
User enters a string in the first text box.
User enters string to be replaced (part of the first string) in the second text box.
User enters new string to insert in third text box.
Button – calls a function to perform the replacement and displays the results in all uppercase.
I am using document.querySelector("myID").value; to grab the value entered, but i am not sure if i should be using replace() for this. Or if the variable needs to be converted to something else. (very confused)
If anyone could point me in the right direction it would be much appreciated.
You could use something like this:
<body>
<textarea id="textArea" ></textarea><br>
<input id="input1" /><br>
<input id="input2" /><br>
<input type="button" value="Replace" onclick="doReplace()" />
<div id="output">OUTPUT!</div>
<script>
function doReplace() {
var getById = document.getElementById.bind(document);
var get = function(id) { return getById(id).value };
var text = get('textArea'),
input1 = get('input1'),
input2 = get('input2'),
div = getById('output');
var regex = new RegExp(input1, "g"); // to replace globally you need this!
div.innerHTML = text.replace(regex, input2).toUpperCase();
}
</script>
</body>
EDIT:
jsfiddle.net
Javascript by default recognizes everything as string, when given a string operation. In this case you could use replace() method directly without any conversions.
I am trying to use angularjs dynamic form elements but when I type something in inputs, there are appearing many special characters []"": and field, value .etc in textarea, I just want to see in textarea what I wrote in inputs ,
this is what I am working on it http://plnkr.co/edit/JbjqjAoQ3odBhXF1a13r?p=preview
sorry for my poor english,,,
What Chris Story says is correct. You are trying to model the text value of the <textarea> to an array of objects, inputs
If you are just trying to display the results like it seems, a <textarea> is not the way to go. You can display them in a simple list, like this:
<ul>
<li ng-repeat="input in inputs">{{input.field}} = {{input.value}}</li>
</ul>
EDIT
To display it in a <textarea>, you will need to store the list as string to use. This can be done by appending each item into a single string each time there is a change to an input value using ng-change.
Change the inputs to utilize the ng-change:
<div ng-repeat="input in inputs">
<input type="text" ng-model="input.field" ng-change="inputChanged()" />
<input type="text" ng-model="input.value" ng-change="inputChanged()" />
<button ng-click="removeInput($index); inputChanged()">Remove</button>
</div>
And create the function that is called to maintain the string:
$scope.inputChanged = function() {
$scope.listString = "";
for(var i = 0; i < $scope.inputs.length; i++) {
var field = $scope.inputs[i].field;
var value = $scope.inputs[i].value;
$scope.listString += field + " = " + value + "; ";
}
}
And finally, use this $scope.listString in the <textarea>:
<textarea rows="22" cols="55" ng-model="listString"></textarea>
I have forked your Plunkr here
The behavior does not make much sense from a UX perspective, but this seems to match your requirement. An option that might make sense is to add disabled="true" to the <textarea> so it can not be edited.
The issue is that you are rendering {{inputs}} and inputs is an Array.
I need help creating a form with the following
TEXTFIELD(will be used to enter 7digit model numbers)
An image placeholder (will change the image placeholder's src based on a url for example it will become src="http://yourwebsite.com/product/TEXTFIELD.jpg)
I need to somehow get the the H1 tag values from within the product's url
#3 IS STILL UNSOLVED !
I'm REALLY desperate for any type of help.
I've googled the entire day REALLY need assistance.
Thank You !
I have some code below that helps visualize what I'm kinda looking for.
Please contact me if you need clarification or if I'm a bit confusing.
<form name="form1" method="post" action="">
<p>7-digit product#
<input type="text" name="model" id="model">
</p>
<p>
<input name="start" type="hidden" id="start" value="http://www.mywebsite.com/Products/">
</p>
<p>
<input name="end" type="hidden" id="end" value=".jpg">
</p>
<p><img name="proudctimage" src="=#start#model#end" width="32" height="32" alt=""></p>
</form>
<script>
var model_input = document.getElementById('model');
var start = document.getElementById('start');
var end = document.getElementById('end');
var image = document.getElementsByTagName('img');
model_input.onkeyup = function(e){
image[0].src = start.value + model_input.value + end.value;
}
</script>
~EDITED 9:00AM 5/29/12~
The Values entered in the textfield gets deleted if you hit enter
I need a way to grab a product's description stored in a H1 tag using the respective URL (The URL is the model number of what is entered in the textfield but uses a slightly different url structure that is different than the one used to grab images , see below ... http://mywebsite.com/ProductDetails.aspx?productid=TEXTFIELD)
***I Should make note that the URL used to get the H1 data will be a "cross domain" & not necessarily on the some domain. I read that jquery may not make requests on cross domains
You could use Jquery to do this easily.
Grab a copy of Jquery from http://www.jquery.com or use the CDN version by pasting this into your head section:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
Here's a simplified version:
If the start and end parts of your URL are not going to change you could simplify your form:
<form>
<label>Model Num</label>
<input type="text" name="model" id="model" />
<input type="button" value="Update Image" id="update" />
</form>
<img src="" />
Then With the following Jquery code, you can detect a click on the update button, grab the code from the text box and change the image src attribute to
http://mysite.com/products/typed_code_here
Just paste the jquery code (and the script tags) into your head section
<script>
$(document).on('click','#update',function(){
$('img').attr('src','http://mysite.com/product/'+$('#model').val()+'.jpg');
});
</script>
If you want to do this without Jquery and if your html has to remain as above, you could use the following along with your original html (watch out for spelling mistakes in your code):
<script>
var model_input = document.getElementById('model');
var start = document.getElementById('start');
var end = document.getElementById('end');
var image = document.getElementsByTagName('img');
model_input.onkeyup = function(e){
image[0].src = start.value + model_input.value + end.value;
}
</script>
The onkeyup event could be changed to blur, change etc depending on how you want to update the image. I'd suggest a button such that the user can update the image when they believe the code is valid.
Update
The following github project has made progress on the front of cross domain html requests with jQuery. https://github.com/padolsey/jQuery-Plugins/tree/master/cross-domain-ajax/
Basically you'd just need to grab the product page via ajax (jQuery.ajax()) and then in the ajax callback you'd have to scan the returned HTML for the h1 element. Ultimately cross domain ajax is a design pattern and there are best practices associated with it. Grabbing the whole HTML page for the sake of an h1 element is not very effective. Consider revising your approach and be sure to check any copyright laws/terms and conditions if the site you're referencing is not your own.
If your using jquery, you could do this:
$(function () {
$('#model').change(function () {
$('img[name="productimage"]').attr('src', $('#start').val() + $('#model').val() + $('#end').val());
});
});
In your html take a hidden div. suppose
<div id="loadSource"></div>
$('#model').blur(function () {
var modelVal = $.trim(this.value),
startVal = $.trim($('#start').val()),
endVal = $.trim($('#end').val());
if( modelVal && startVal && endVal) {
var imgUrl = startVal + modelVal + endVal,
siteUrl = startVal + modelVal;
$('img[name="productimage"]')
.attr('src', );
// process to get h1 tag
$('#loadSource').load(''+ siteUrl +' h1', function() {
console.log( $('#loadSource h1').text() );
});
}
});
In the string
some text <p id='item_1' class='item'>multiline content\r\n\r\n for <br/>remove</p><br clear='all' id='end_of_item_1'/><p id='item_2' class='item'>another multiline content\r\n\r\n</p><br clear='all' id='end_of_item_2'/>
I need to remove
<p id='item_1' class='item'>multiline content\r\n\r\n for <br/>remove</p><br clear='all' id='end_of_item_1'/>
Can't find a way how to do it.
var id = 'item_1';
var patt=new RegExp("<p id='"+id+"'(.)*|([\S\s]*?)end_of_"+id+"'\/>","g");
var str="some text <p id='item_1' class='item'>multiline content\r\n\r\n for <br/>remove</p><br clear='all' id='end_of_item_1'/><p id='item_2' class='item'>another multiline content\r\n\r\n</p><br clear='all' id='end_of_item_2'/>";
document.write(str.replace(patt,""));
The result is
some text for
<br>
remove
<p></p>
<br id="<p id=" class="item" clear="all" item_2'="">
another multiline content
<p></p>
<br id="end_of_item_2" clear="all">
Please help to solve this.
Here's the regex for the current scenario. When the regex approach eventually breaks, remember that we warned that parsing HTML with regex was a fool's errand. ;)
This:
var s = "some text <p id='item_1' class='item'>multiline content\r\n\r\n for <br/>remove</p><br clear='all' id='end_of_item_1'/><p id='item_2' class='item'>another multiline content\r\n\r\n</p><br clear='all' id='end_of_item_2'/><ul><li>";
var id = 'item_1';
var patt = new RegExp ("<p[^<>]*\\sid=['\"]" + id + "['\"](?:.|\\n|\\r)*<br[^<>]*\\sid=['\"]end_of_" + id + "['\"][^<>]*>", "ig")
var stripped = s.replace (patt, "");
Produces this:
"some text <p id='item_2' class='item'>another multiline content
</p><br clear='all' id='end_of_item_2'/><ul><li>"
Why can't you use the DOM API to remove it? (add everything to the document, and then remove what you don't need)
var item1 = document.getElementById('item_1'),
endOfItem1 = document.getElementById('end_of_item_1');
item1.parentNode.removeChild(item1);
endOfItem1.parentNode.removeChild(endOfItem1);
I need to assume a bit of unspoken constraints from your question, to get this to work:
Am I right in guessing, that you want a regex, that can find (and then replace) any 'p' tag with a specific id, up to a certain tag (like e.g. a 'br' tag) with an id of 'end_of_[firstid]'?
If that is correct, than the following regex might work for you. It may be, that you need to modify it a bit, to get JS to accept it:
<p\s+id='([a-zA-Z0-9_]+)'.*?id='end_of_\1'\s*\/>
This will give you any constellation with the criteria, describled above, and the name if the id as group 1, It should now be a simple task, to check if group1 contains the id you want to remove and then replace the whole match with an empty string.
If I understand your example correcty (I am not that good with JavaScript and my RegEx was based rather on the general perl-regex fashion) you could maybe do something like the following:
var patt=new RegExp("<p\s+id='"+id+"'.*?id='end_of_"+id+"'\s*\/>","g");
That way, you don't have to worry about group matching, although I find it to be more elegant, to match the id you wanted via a group instead of inserting it into the RegEx.