I'm trying to highlight a list element using:
element.id = 'ACT_3'
$('#' + element.id).addClass('highlight');
Javascript
function selectItemId(element) {
$('#' + element.id).addClass('highlight');
var eleID = element.id;
//highlight selection(s)
selectItemId
if (document.getElementById(eleID).className == "smallfieldchecked") {
document.getElementById(eleID).className = "smallfield";
}
else {
document.getElementById(eleID).className = "smallfieldchecked";
}
Items.selectedForRemoval.length = 0;
// build a list of Selected Items
if (elementInDocument(document.getElementById(mainGrid))) {
var ul = document.getElementById(mainGrid);
var lis = ul.childNodes;
for (var x = 0; x < lis.length; x++) {
if (document.getElementById(lis[x].id)) {
if (document.getElementById(lis[x].id).className == "smallfieldchecked") {
Items.selectedForRemoval.push(lis[x].id.replace(rowPrefix, ''));
}
}
}
}
}
CSS
.highlight {
background-color: cyan;
font-weight: bold;
}
I think the addClass() is working but it's being overridden a few lines below by document.getElementById(eleID).className = "...."
Try to put the addClass line after the if ... else block
Here are a few variations of how to fix the issue. Sélim Achour is correct in the cause of the problem and how to fix it.
Every time you do a query, you have to search the DOM for it, so these examples will put the element into a reuseable var.
function selectItemIDFromMainGrid(element) {
var $element = $('#' + element.id);
$element.addClass('highlight');
//highlight selection(s)
selectItemIDFromMainGrid // <-- not sure what this is
if ($element.hasClass("smallfieldchecked")) {
$element.removeClass('smallfieldchecked').addClass("smallfield");
}
else {
$element.removeClass('smallfield').addClass("smallfieldchecked");
}
// remaining code removed for brevity.
}
This version also works, as Sélim Achour pointed out. However, you will have to debug a similar situation if you have more classes used in the future.
function selectItemIDFromMainGrid(element) {
// jquery-wrapped element
var $element = $('#' + element.id);
// actual DOM element.
var domElement = $element[0];
//highlight selection(s)
selectItemIDFromMainGrid // <-- not sure what this is
if ($element.hasClass("smallfieldchecked")) {
domElement.className = "smallfield";
}
else {
domElement.className = "smallfieldchecked";
}
// adding the class down here after setting the class above
// makes this get appended. the assignments above make a single class assignment.
$element.addClass('highlight');
// remaining code removed for brevity.
}
Or you can skip the jQuery for adding the highlight class.
function selectItemIDFromMainGrid(element) {
// jquery-wrapped element
var $element = $('#' + element.id);
// actual DOM element.
var domElement = $element[0];
//highlight selection(s)
selectItemIDFromMainGrid // <-- not sure what this is
if ($element.hasClass("smallfieldchecked")) {
domElement.className = "smallfield highlight";
}
else {
domElement.className = "smallfieldchecked highlight";
}
// remaining code removed for brevity.
}
Related
I need to hide a <section> in my HTML with JavaScript while highlighting the text or to show it otherwise.
My selection works in this way:
document.addEventListener('click', function(){
var selected = window.getSelection();
var links = document.getElementsByClassName("linkAnnotation");
if (selected == '') {
links.setAttribute('style', 'display:block;');
} else {
links.setAttribute('style', 'display:none;');
}
})
but this setAttribute does not work as other hundreds of tries that I have done.
Can someone save my life??
Every setAttribute, style.innerHTML, etc.
when you are selecting links it retuns HTMLCollection forExample : [linkAnnotation1, linkAnnotation2] it not returns one element because your code doesnot works you must write for loop example:
document.addEventListener('click', function () {
var selected = window.getSelection();
var links = document.getElementsByClassName('linkAnnotation')
if (selected == '') {
for (let i = 0; i <= links.length - 1; i++) {
links[i].setAttribute('style', 'display:block')
}
}else {
for(let i = 0; i <= links.length - 1; i++) {
links[i].setAttribute('style', 'display:none')
}
}
})
getElementsByClassName returns a HTMLCollection (Which returns an array-like object of all child elements which have all of the given class name(s)). You have to iterate through all of those elements and change properties.
So, you have to use the following code:
document.addEventListener('click', function() {
var selected = window.getSelection();
var links = document.getElementsByClassName("linkAnnotation");
if (selected === '') {
links.forEach(val => { val.setAttribute('style', 'display:block;'); });
} else {
links.forEach(val => { val.setAttribute('style', 'display:none;'); });
}
})
I am working on a xamarin.ios application to show the content in a text file into webview. I could able to display the content.
Now I need to add search feature, so that the selected string needs to highlighted and SCROLL need to position in to the search text. I am using below Javascript to highlight the searched text and highlighting is working as expected.
string startSearch = "MyApp_HighlightAllOccurencesOfString('" + searchStr + "')";
this.webView.EvaluateJavascript (startSearch);
How can I move the scroll position to the searched string using this webview?
Thanks in advance
Roshil K
You can use the code snippet to reset the scroll position of the WebView, like this:
webView.ScrollView.ContentOffset = new CGPoint(0,50);
But you have to know the (x,y) point of the related string. I am not familiar with Javascript, maybe it can be returned by your JS code.
Also, I found a solution via JS which maybe help you here:https://stackoverflow.com/a/38317775/5474400.
I got is solved by adding the below javascript to my existing "MyApp_HighlightAllOccurencesOfString" javascript.
var desiredHeight = span.offsetTop - 140;
window.scrollTo(0,desiredHeight);
My Complete Javascript is below.
this.webView.EvaluateJavascript ("// We're using a global variable to store the
number of occurrences
var MyApp_SearchResultCount = 0;
// helper function, recursively searches in elements and their child nodes
function MyApp_HighlightAllOccurencesOfStringForElement(element,keyword) {
if (element) {
if (element.nodeType == 3) { // Text node
while (true) {
var value = element.nodeValue; // Search for keyword in text node
var idx = value.toLowerCase().indexOf(keyword);
if (idx < 0) break; // not found, abort
var span = document.createElement(\"span\");
var text = document.createTextNode(value.substr(idx,keyword.length));
span.appendChild(text);
span.setAttribute(\"class\",\"MyAppHighlight\");
span.style.backgroundColor=\"yellow\";
span.style.color=\"black\";
text = document.createTextNode(value.substr(idx+keyword.length));
element.deleteData(idx, value.length - idx);
var next = element.nextSibling;
element.parentNode.insertBefore(span, next);
element.parentNode.insertBefore(text, next);
element = text;
var desiredHeight = span.offsetTop - 140;
window.scrollTo(0,desiredHeight); MyApp_SearchResultCount++;\t// update the counter
}
} else if (element.nodeType == 1) { // Element node
if (element.style.display != \"none\" && element.nodeName.toLowerCase() != 'select') {
for (var i=element.childNodes.length-1; i>=0; i--) {
MyApp_HighlightAllOccurencesOfStringForElement(element.childNodes[i],keyword);
}
}
}
}
}
// the main entry point to start the search
function MyApp_HighlightAllOccurencesOfString(keyword) {
MyApp_RemoveAllHighlights();
MyApp_HighlightAllOccurencesOfStringForElement(document.body, keyword.toLowerCase());
}
// helper function, recursively removes the highlights in elements and their childs
function MyApp_RemoveAllHighlightsForElement(element) {
if (element) {
if (element.nodeType == 1) {
if (element.getAttribute(\"class\") == \"MyAppHighlight\") {
var text = element.removeChild(element.firstChild);
element.parentNode.insertBefore(text,element);
element.parentNode.removeChild(element);
return true;
} else {
var normalize = false;
for (var i=element.childNodes.length-1; i>=0; i--) {
if (MyApp_RemoveAllHighlightsForElement(element.childNodes[i])) {
normalize = true;
}
}
if (normalize) {
element.normalize();
}
}
}
}
return false;
}
// the main entry point to remove the highlights
function MyApp_RemoveAllHighlights() {
MyApp_SearchResultCount = 0;
MyApp_RemoveAllHighlightsForElement(document.body);
}");
What impact does eventlisteres have? Im talking about big numbers, here's an example:
There's only x amount of .marker at first
All children are added via JS when .marker is clicked - eventlistener
Each child does it's own thing which means each of them have their own eventlisteners
<!-- Final HTML of single .marker when it has been clicked -->
<div class="marker">
<div class="remove"></div>
<div class="change"></div>
<div class="add"></div>
<div class="drag"></div>
</div>
var count = 20 000;
for(i = 0; i < count; i++) {
var marker = document.createElement('div');
marker.className = 'marker';
someParentElement.appendChild(marker);
marker.click( function() {
//Create child elements
var remove = document.createElement('div');
remove.className = 'remove';
marker.appendChild(remove);
var change = document.createElement('div');
change.className = 'change';
marker.appendChild(change);
var add = document.createElement('div');
add.className = 'add';
marker.appendChild(add);
var drag = document.createElement('div');
drag.className = 'drag';
marker.appendChild(drag);
//Children eventlisteners
remove.click( function() {
//Do it's thing
});
change.click( function() {
//Do it's thing
});
add.click( function() {
//Do it's thing
});
drag.click( function() {
//Do it's thing
});
});
}
Please don't mind other things, e.g creating 20 000 elements programmatically. My question is this: what would be the impact of having all these eventlisteners with all this code in them? Does it even matter what or how much code is inside eventlistener as long as it hasn't been triggered?
Try using event delegation , single event handler. See switch , .is()
var count = 100;
for (i = 0; i < count; i++) {
var marker = document.createElement('div');
marker.className = 'marker';
marker.innerHTML = marker.className + " " + i;
document.body.appendChild(marker);
//Create child elements
var remove = document.createElement('div');
remove.className = 'remove';
remove.innerHTML = "remove" + i;
marker.appendChild(remove);
var change = document.createElement('div');
change.className = 'change';
change.innerHTML = "change" + i;
marker.appendChild(change);
var add = document.createElement('div');
add.className = 'add';
add.innerHTML = "add" + i;
marker.appendChild(add);
var drag = document.createElement('div');
drag.className = 'drag';
drag.innerHTML = "drag" + i;
marker.appendChild(drag);
//Create child elements
}
var check = function(args) {
alert(args.innerHTML.replace(/[^\d+]/g, ""))
}
var obj = {
remove: check,
change: check,
add: check,
drag: check
}
var message = function(name) {
console.log(name)
}
$("body").on("click", ".marker", function(event) {
var name = event.target.className;
switch (name) {
case "remove":
/* do stuff */
message(name);
break;
case "change":
/* do stuff */
message(name);
break;
case "add":
/* do stuff */
message(name);
break;
case "drag":
/* do stuff */
message(name);
break;
default:
/* do stuff */
alert(name);
break;
}
// utilizing `.is()`
if ($(event.target).is(".remove")) {
// do stuff
event.target.innerHTML += "clicked"
}
if ($(event.target).is(".change")) {
// do stuff
event.target.innerHTML += "clicked"
}
if ($(event.target).is(".add")) {
// do stuff
event.target.innerHTML += "clicked"
}
if ($(event.target).is(".drag")) {
// do stuff
event.target.innerHTML += "clicked"
}
if (!$(event.target).is(".marker")) {
// utilizing an object
obj[event.target.className](event.target)
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
Creating event handlers for so many things which are repeated feels like a waste of CPU cycles, plus memory to manage so many event listeners.
Instead, it would be preferrable to use event bubbling/delegation to listen to the click events from a parent node (as close an ancestor element as possible would be ideal) and see what element triggered the event and call the appropriate code accordingly.
This would be a one-time bind, and should also catch dynamically added elements if done right.
Examples with jQuery that are also explained quite well include the following
https://learn.jquery.com/events/event-delegation/
http://api.jquery.com/on/
Though you are not limited to just jQuery to implement this.
Hope that helps.
I'm trying to replace the <li> with 1. 2. 3. respectively. I managed to change the <li> to a number, but that number is 0. The loop doesn't want to work. To be honest, this method may be impossible.
Take a look at the Fiddle if you'd like.
This is my function(){...} :
function doIt(){
var input = document.getElementById("input");
var li = /<li>/; // match opening li
var liB = /<\/li>/; // match closing li
var numberOfItems = input.value.match(li).length; // number of lis that occur
for(var i = 0; i < numberOfItems; i++) {
insertNumber(i); // execute insertNumber function w/ parameter of incremented i
}
function insertNumber(number){
input.value = input.value.replace(li, number + "." + " ").replace(liB, "");
}
}
I understand the insertNumber(){...} function is not necessary.
Here's an alternative method, turning your HTML textarea contents into DOM elements that jQuery can manipulate and managing them that way:
function doIt() {
var $domElements = $.parseHTML( $('#input').val().trim() ),
output = [],
i = 1;
$.each($domElements, function(index, element) {
if($(this).text().trim() != '') {
output.push( i + '. ' + $(this).text().trim() );
i++;
}
});
$('#input').val(output.join('\n'));
}
So im trying to remove HTML div's from it's parent div.
I have a div which contains the div that need to be removed, selectedDivs.
However my current function refuses to remove more then 1 item from it's parent div...
Here's what i tried:
Console output: http://pastebin.com/KCeKv1pG
var selectedDivs = new Array();
canvas.innerHTML += "<div id="+currDev+" class='DRAGGABLE' onClick='addBorder(this)>" + "<img src='/devices/" + device + ".gif'></img></div>";
function addBorder(e) {
if (ctrlBeingpressed == true) {
selectedDivs.push(e);
e.style.border = "2px dotted black";
}
}
function deleteSelected() {
console.log(selectedDivs);
var len = selectedDivs.length;
for (var i = 0, len; i < len; i++){
console.log("before html remove: " + selectedDivs.length);
var node = selectedDivs[i];
node.parentNode.removeChild(node);
console.log("after html remove: " + selectedDivs.length);
for (var i in racks)
{
console.log(i);
if(node.id == racks[i].refdev)
{
console.log("Found in rack");
for (z = 1; z < racks[i].punkt.length; z++)
{
if(racks[i].punkt[z] != undefined)
{
if(racks[i].punkt[z].y.indexOf("S") > -1) //If it's an already defined point at an S card
{
//Clearing the TD
$("#sTab tr:eq("+(cardsS.indexOf(racks[i].punkt[z].y)+1)+") td:eq("+(racks[i].punkt[z].x-1)+")").html(" ");
$("#sTab tr:eq("+(cardsS.indexOf(racks[i].punkt[z].y)+1)+") td:eq("+(racks[i].punkt[z].x-1)+")").css("background-color","#E6E6E6");
}
else // Then it must be a P or V card
{
$("#pvTab tr:eq("+(cardsPV.indexOf(racks[i].punkt[z].y)+1)+") td:eq("+(racks[i].punkt[z].x-1)+")").html(" ");
$("#pvTab tr:eq("+(cardsPV.indexOf(racks[i].punkt[z].y)+1)+") td:eq("+(racks[i].punkt[z].x-1)+")").css("background-color","#E6E6E6");
}
}
}
console.log("Found in rack, breaking this loop");
delete racks[i];
break;
}
}
}
As discussed in the comments, there's a problem with resetting the value of the i variable within the nested loop. I took the liberty of editing the code to the way I would write it. I jQueried up some things since you're already using it anyway. (This code assumes you can target IE 9 or later and thus use Array.prototype.forEach and also that racks is an array, which seemed to be the case from the original.)
var selectedDivs = [];
$(canvas).append("<div id="+currDev+" class='DRAGGABLE' onClick='markSelected(this)'><img src='/devices/" + device + ".gif'></img></div>");
function markSelected(div) {
if (ctrlBeingpressed == true) {
selectedDivs.push(div);
$(div).css("border", "2px dotted black");
}
}
function deleteSelected() {
var i, z, deletedDivIDs = [];
console.log(selectedDivs);
selectedDivs.forEach(function(selectedDiv, index, selectedDivs) {
console.log("Removing", selectedDiv, "at index", index);
divIDs.push(selectedDiv.id);
selectedDiv.parentNode.removeChild(selectedDiv);
});
racks.forEach(function(rack, index, racks) {
console.log(i);
if(deletedDivIDs.indexOf(rack.refdev) !== -1) {
console.log("Found in rack");
for (z = 1; z < rack.punkt.length; z++) {
if(rack.punkt[z] !== undefined) {
if(rack.punkt[z].y.indexOf("S") > -1) {//If it's an already defined point at an S card
//Clearing the TD
$("#sTab tr:eq("+(cardsS.indexOf(rack.punkt[z].y)+1)+") td:eq("+(rack.punkt[z].x-1)+")").css("background-color","#E6E6E6").empty();
}
else { // Then it must be a P or V card
$("#pvTab tr:eq("+(cardsPV.indexOf(rack.punkt[z].y)+1)+") td:eq("+(rack.punkt[z].x-1)+")").css("background-color","#E6E6E6").empty();
}
}
}
racks[rack] = undefined;
}
});
}
I didn't have a chance to test this in real code since we still don't know what racks looks like, but hopefully this gets you further down the road.
you have created nested for loops with the same var i=0, It could be your problem.
And the other point I like to point out is, if racks is an array you'd better not use for(var i in racks) because it would scan all other prototype attributes in your Array.prototype, which depends on what libraries you have used in your page. and If racks is not an array, it would scan all other properties in your Object.prototype, what I mean is, if it is just a iteration using for(var i in racks) is not safe, because adding a new Javascript library could mess with your code.