Dynamically highlight text in <li> based on checked checkboxes - javascript

I have a webpage that generate <li> from a Json object passed from a flask app route. I have a set of checkboxes generated dynamically from the same Json object. What I wanted to do is highlight the words in the <li> text ... </li> if there is a match to any checked checkbox.
This what I have done so far.
Java script to capture checked checkboxes and find matches in <li>
$(".topic-check").change(function(){
var chkTopicIDs = checkTopics();
console.log(chkTopicIDs);
list_items = document.querySelectorAll(".sent");
for (item of list_items){
var text = item.textContent;
if (new RegExp(chkTopicIDs.join("|")).test(text)){
item.classList.add("highlight");
}
else {
item.classList.remove("highlight");
}
}
});
function checkTopics(){
$checkbox = $('.topic-check');
var chkArray = [];
chkArray = $.map($checkbox, function(el){
if(el.checked){return el.id}
});
return chkArray;
}
CSS to highlight
.highlight{
background: yellow;
}
HTML template with jinja tags
...
<ul>
{% for sent in turn['list_of_sentences'] %}
<li class="sent">{{sent['text']}}</li>
{% endfor %}
</ul>
...
<div class="card-body">
{% for topic in response['topics'] %}
<div>
<input type="checkbox" id="{{topic}}" class="topic-check" onclick="func1()" /> <label class="checkbox-inline" >{{ topic }}</label> <br/>
</div>
{% endfor %}
</div>
...
I did a sanity check to see whether I get the list of checked checkboxes. The console displays IDs, so that part worked. But I don't see the highlighting of text regardless of checkboxes are checked.
Side note: I also see the following error in JS console.
ReferenceError: func1 is not defined

1) You have a typo here: item.classList.add("highlist") - should be highlight correct?
2) onclick="func1()" this is causing your func1 is not defined, just remove it.
3) I don't know if that's the case, but $(".topic-check").change won't work on dynamically added HTML. You need something like $(".card-body").on("change", ".topic-check", function)
4) You should store new RegExp(chkTopicIDs.join("|")) as a variable outside the loop for increased performance

Related

Get attribute from a specific element of a class

Basically I have to develop a Tic-Tac-Toe game, here is the HTML file which I can't rewrite only reformat a bit, but the idea should stay the same.
{% block content %}
<nav class="navbar fixed-top navbar-light">
<button id="retry-button" class="btn btn-success">Try again?</button>
Reset settings
</nav>
<div id="game-board" class="mb-3" data-row-num="{{ row_num }}" data-col-num="{{ col_num }}" data-win-size="{{ win_size }}">
{% for row in range(row_num) %}
<div>
{% for col in range(col_num) %}
<div class="game-cell"
data-coordinate-x="{{ col }}"
data-coordinate-y="{{ row }}"></div>
{% endfor %}
</div>
{% endfor %}
</div>
{% endblock %}
As you can see i have a game-cell class which contains by default 9 elements. I would like to return the data-coordinate-x and data-coordinate-y when I click one of the game-cells. I had a previous try but if I clicked it returned all of the blocks not just the one i clicked on. I have to write it in Js. If you can point me in the right direction that's more than enough for me.
Thanks!
If I understood correctly, you need to access data attributes of your game-cell element. In order to do this, you need to select the element by some ID or class. I have modified your code a little to make it run inside stackoverflow`s platform. I have added an ID which i called "unique" and I also set some values into your coordinate-x and y data attributes. Please review the code bellow and see how I managed to get those data attributes. It's important to notice that this is not the only way to access them.
var gamecell = document.getElementById('unique');
console.log(gamecell.dataset.coordinateX);
console.log(gamecell.dataset.coordinateY);
<nav class="navbar fixed-top navbar-light">
<button id="retry-button" class="btn btn-success">Try again?</button>
Reset settings
</nav>
<div id="game-board" class="mb-3" data-row-num="{{ row_num }}" data-col-num="{{ col_num }}" data-win-size="{{ win_size }}">
<div>
<div class="game-cell" id="unique"
data-coordinate-x="172"
data-coordinate-y="273"></div>
</div>
</div>
Its also possible to get these values using the getAttribute method.
var elem = document.getElementById('unique');
var coordX = elem.getAttribute('data-coordinateX');
var coordY = elem.getAttribute('data-coordinateY');
Please, take a look at this page, it explains some aspects of data attributes:
https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
Simply access your clicked game-cell by: (it will find the clicked coordinateX and coordinateY)
document.querySelectorAll('.game-cell').forEach((game) => {
game.addEventListener('click',function(event){
console.log(game.dataset.coordinateX);
console.log(game.dataset.coordinateY);
});
});
you must to get your element by class name or id(add an id)
than you can get its attributes like this
let gameCell = document.getElementById('game-cell-id');// id for example
gameCell.getAttribute('data-coordinate-x')

Django and JavaScript: filtering not working paused on exception

I am trying to filter a table by the room name of the records which are in each row. My table rows look like this:
<tr data-room="{{ record.room.room_name|lower|field_name_format}}">
So, when the user checks kitchen, rows related to kitchen shows up in the table and not rows related to other rooms.
And this is the code in the header of my HTML:
{% for room in user_related_rooms %}
document.querySelector('#{{room.room_name|lower|field_name_format}}').addEventListener('change',function (evt) {
updateTableView("{{room.room_name|lower|field_name_format}}", evt.target.checked);
});
{% endfor %}
function updateTableView(room_name, bVisible) {
var dataSelectorVal = "";
switch (room_name)
{
{% for room in user_related_rooms %}
case "{{room.room_name|lower|field_name_format}}":
dataSelectorVal = ".site-table tbody tr[data-room='{{room.room_name|lower|field_name_format}}']";
break;
{% endfor %}
}
$(".site-table tbody tr").has(dataSelectorVal).css('display', bVisible ? "" : "none");
}
Here is the code for the filter:
<!-- Filters -->
<div class="col-md-1">
<h1>Filters</h1>
<form>
<span> by room:</span>
<div class="side-filter-list">
<ul>
{% for room in user_related_rooms %}
<li class="flex-field">
<input type="checkbox" id="cb_{{room.room_name|lower|field_name_format}}" />
<label for="{{room.room_name}}">{{room.room_name}}</label>
</li>
{% endfor %}
</ul>
</div>
</form>
</div>
The browser pauses on the exception. I get error on this line, living_room being the first room in the loop (i.e. the first iteration of the loop):
document.querySelector( '#cb_living_room' ).addEventListener('change', function (evt) {
It seems the above line returns null whereas when I comment out the code and use the console to look for it, it finds it without complaining:
document.querySelector( '#cb_living_room')
Console gives me the output:
<input id="cb_living_room" type="checkbox">
What am I doing wrong? What is going on?

Jquery toggle (visible/invisible) for only the item clicked on in a template-generated html list

Code
<ul>
{% for item in lis %}
<li>
<div id="single-toggle">|Toggle|</div>
<div class="visible-when-folded">
<div class="name">{{ item.name }}</div>
<div class="date">{{ item.date }}</div>
</div>
<div class="invisible-when-folded">
<div class="about">{{ item.about }}</div>
<div class="contact_info">{{ item.contact_info }}</div>
</div>
</li>
{% endfor %}
</ul>
Example output code
|Toggle|
Peter
24-04-1990
A friendly guy
0474657434
|Toggle|
Martha
22-02-1984
An amazing gal
0478695675
|Toggle|
William
12-11-1974
An oldie
0478995675
Desired behavior
I would like that whenever you click on |Toggle| the about(e.g. A friendly guy)
and contact_info(e.g. 0474657434) part dissapear/reappear.
Attempt at solution
$(function(){
$("#single-toggle").click(
function(){ $("div.invisible-when-folded").toggle(); } );
});
But unfortunately this toggles the fields for each item in the list as opposed to only the one I click on.
Edit
views.py
from django.shortcuts import render_to_response
from django.template import RequestContext
def toggle(request):
lis = [{'name':'Peter', 'date':'24-04-1990', 'about':'A friendly guy',
'contact_info':'0474657434' },
{'name':'Martha', 'date':'22-02-1984', 'about':'An amazing gal',
'contact_info':'0478695675' },
{'name':'William', 'date':'12-11-1974', 'about':'An oldie',
'contact_info':'0478995675' }]
return render_to_response('page.html', {'lis':lis},
context_instance=RequestContext(request))
You need to pass the current object as context in the selector to get the element related to event source object. You also need to use class instead of id or generate unique ids for div with id = single-toggle as html elements are supposed to have unique ids.
Live Demo
I have give the div with id a class="single-toggle"
Change
$("div.invisible-when-folded").toggle();
To
$("div.invisible-when-folded", this).toggle();
You code
$(function(){
$("#single-toggle").click(
function(){ $("div.invisible-when-folded", this).toggle(); } );
});
You need to focus the function on the div within the clicked div... The actual code you need to use is:
$(function(){
$("#single-toggle").click(
function(){ $("div.invisible-when-folded", this).toggle(); } );
});

I am having a few problems trying to create a jquery live search function for basic data set?

I am designing a simple jquery live search function within a widget on a site i'm developing. I have borrowed some code I found and it is working great. The problem is though that instead of using a list like this:
<ul>
<li>Searchable Item 1</li>
<li>Searchable Item 2</li>
etc
I am using a list like this:
<ul>
<li>
<a href="#">
<div class="something>
<img src="something.jpg">
<p>Searchable Item 1</p>
</div>
</a>
</li>
etc.
As you can see the text I want to search is in the p tag. The functions I have used are searching all the other stuff (a href, div, img) and matching text found in those tags as well as the item within the p tag. Sorry if my explanation is a bit confusing but I will show you an example of the code here:
//includes im using
<script type="text/javascript" src="js/jquery-1.7.min.js" ></script>
<script type="text/javascript" src="js/quicksilver.js"></script>
<script type="text/javascript" src="js/jquery.livesearch.js"></script>
//document ready function
$(document).ready(function() {
$('#q').liveUpdate('#share_list').fo…
});
//actual search text input field
<input class="textInput" name="q" id="q" type="text" />
//part of the <ul> that is being searched
<ul id="share_list">
<li>
<a href="#">
<div class="element"><img src="images/social/propellercom_icon.jpg… />
<p>propeller</p>
</div>
</a>
</li>
<li>
<a href="#">
<div class="element"><img src="images/social/diggcom_icon.jpg" />
<p>Digg</p>
</div>
</a>
</li>
<li>
<a href="#">
<div class="element"><img src="images/social/delicios_icon.jpg" />
<p>delicious</p>
</div>
</a>
</li>
</ul>
also here is the jquery.livesearch.js file I am using
jQuery.fn.liveUpdate = function(list){
list = jQuery(list);
if ( list.length ) {
var rows = list.children('li'),
cache = rows.map(function(){
return this.innerHTML.toLowerCase();
});
this
.keyup(filter).keyup()
.parents('form').submit(function(){
return false;
});
}
return this;
function filter(){
var term = jQuery.trim( jQuery(this).val().toLowerCase() ), scores = [];
if ( !term ) {
rows.show();
} else {
rows.hide();
cache.each(function(i){
var score = this.score(term);
if (score > 0) { scores.push([score, i]); }
});
jQuery.each(scores.sort(function(a, b){return b[0] - a[0];}), function(){
jQuery(rows[ this[1] ]).show();
});
}
}
};
I believe the problem lies here:
var rows = list.children('li'),
cache = rows.map(function(){
return this.innerHTML.toLowerCase();
});
it is just using whatever it finds between the li tags as the search term to compare against the string entered into the text input field. The search function actually does work but seems to find too many matches and is not specific as I am also using a quicksilver.js search function that matches terms that are similar according to a score. When I delete all the other stuff from the li list (a href, img, div, etc) the search function works perfectly. If anyone has any solution to this I would be really greatful, I have tried things like:
return this.children('p').innerHTML but it doesn't work, I'm ok with PHP, C++, C# etc but totally useless with javascript and Jquery, they're like foreign languages to me!
In the jquery.livesearch.js file I believe you can replace this line:
var rows = list.children('li'),
with:
var rows = list.children('li').find('p'),
This should make it so the livesearch plugin will only search the paragraph tags in your list.
You will need to change the .show()/.hide() lines to reflect that you are trying to show the parent <li> elements since you are now selecting the child <p> elements:
Change:
rows.show();//1
rows.hide();//2
jQuery(rows[ this[1] ]).show();//3
To:
rows.parents('li:first').show();//1
rows.parents('li:first').hide();//2
jQuery(rows[ this[1] ]).parents('li').show();//3

Getting value from input control using jQuery

I am using the teleriks treeview control (asp.net mvc extensions), where I may have up to three children nodes, like so (drumroll...... awesome diagram below):
it has its own formatting, looking a bit like this:
<%=
Html.Telerik().TreeView()
.Name("TreeView")
.BindTo(Model, mappings =>
{
mappings.For<Node1>(binding => binding
.ItemDataBound((item, Node1) =>
{
item.Text = Node1.Property1;
item.Value = Node1.ID.ToString();
})
.Children(Node1 => Node1.AssocProperty));
mappings.For<Node2>(binding => binding
.ItemDataBound((item, Node2) =>
{
item.Text = Node2.Property1;
item.Value = Node2.ID.ToString();
})
.Children(Node2 => Node2.AssocProperty));
mappings.For<Node3>(binding => binding
.ItemDataBound((item, Node3) =>
{
item.Text = Node3.Property1;
item.Value = Node3.ID.ToString();
}));
})
%>
which causes it to render like this. I find it unsual that when I set the value it is rendered in a hidden input ? But anyway:...
<li class="t-item">
<div class="t-mid">
<span class="t-icon t-plus"></span>
<span class="t-in">Node 1</span>
<input class="t-input" name="itemValue" type="hidden" value="6" /></div>
<ul class="t-group" style="display:none">
<li class="t-item t-last">
<div class="t-top t-bot">
<span class="t-icon t-plus"></span>
<span class="t-in">Node 1.1</span>
<input class="t-input" name="itemValue" type="hidden" value="207" />
</div>
<ul class="t-group" style="display:none">
<li class="t-item">
<div class="t-top">
<span class="t-in">Node 1.1.1</span>
<input class="t-input" name="itemValue" type="hidden" value="1452" />
</div>
</li>
<li class="t-item t-last">
<div class="t-bot">
<span class="t-in">Node 1.1.2</span>
<input class="t-input" name="itemValue" type="hidden" value="1453" />
</div>
</li>
</ul>
</li>
</ul>
What I am doing is updating a div after the user clicks on a certain node. But when the user clicks on a node, I want to send the ID not the Node text property. Which means I have to get it out of the value in these type lines <input class="t-input" name="itemValue" type="hidden" value="1453" />, but it can be nested differently each time, so the existing code I ahve doesn't ALWAYS work:
<script type="text/javascript">
function TreeView_onSelect(e) {
//`this` is the DOM element of the treeview
var treeview = $(this).data('tTreeView');
var nodeElement = e.item;
var id = e.item.children[0].children[2].value;
...
</script>
So based on that, what is a better way to get the appropriate id each time with javascript/jquery?
edit:
Sorry to clarify a few things
1) Yes, I am handling clicks to the lis of the tree & want to find the value of the nested hidden input field. As you can see, from the telerik code, setting item.Value = Node2.ID.ToString(); caused it to render in a hidden input field.
I am responding to clicks anywhere in the tree, therefore I cannot use my existing code, which relied on a set relationship (it would work for first nodes (Node 1) not for anything nested below)
What I want is, whenever there is something like this, representing a node, which is then clicked:
<li class="t-item t-last">
<div class="t-bot">
<span class="t-in">Node 1.1.2</span>
<input class="t-input" name="itemValue" type="hidden" value="1453" />
</div>
</li>
I want the ID value out of the input, in this case 1453.
Hope this now makes a lot more sense.
if possible would love to extend this to also store in a variable how nested the element that is clicked is, i.e. if Node 1.1.2 is clicked return 2, Node 1.1 return 1 and node 1 returns 0
It's a little unclear what you're asking, but based on your snippet of JavaScript, I'm guessing that you're handling clicks to the lis of the tree & want to find the value of the nested hidden field? If so, you want something like this:
function TreeView_onSelect(e) {
var id = $(e.item).find(".t-input:first").val();
}
Edit: In answer to your follow-up question, you should be able to get the tree depth with the following:
var depth = $(e.item).parents(".t-item").length;
In jQuery you can return any form element value using .val();
$(this).val(); // would return value of the 'this' element.
I'm not sure why you are using the same hidden input field name "itemValue", but if you can give a little more clarity about what you are asking I'm sure it's not too difficult.
$('.t-input').live('change',function(){
var ID_in_question=$(this).val();
});

Categories

Resources