How to construct html list by mapping with common id - javascript

i'm facing problem to construct html list.
i'm expecting same result as shown by (Expected output(Static) Below:)
Question: comm_id having same value should be constructed 1 time
here is what i'm trying
var list = [
{'com_id':12,'text':'Apple'},
{'com_id':12,'text':'Banana'},
{'com_id':91,'text':'cake'},
{'com_id':91,'text':'cup cake'},
];
var dataMap = {}, str = '';
for(var i = 0; i < list.length; i++){
if(!dataMap[list[i]['com_id']]) {
dataMap[list[i]['com_id']] = list[i];
str += '<li>com_id:'+list[i]['com_id']+' <span>'+list[i]['text']+'</span><span>'+list[i]['text']+'</span></li>';
}
}
$('#dynamic_const').html(str);
span{
display:inline-block;
padding:10px;
margin:2px;
background:#eee;
border-radius:20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="dynamic_const">
</div>
<p>Expected output(Static) Below:</p>
<div id="static">
<ul>
<li>com_id:12 <span>Apple</span><span>Banana</span></li>
<li>com_id:91 <span>cake</span><span>cup cake</span></li>
</ul>
</div>
Please help me thanks in advance!!!

var list = [
{'com_id':12,'text':'Apple'},
{'com_id':12,'text':'Banana'},
{'com_id':91,'text':'cake'},
{'com_id':91,'text':'cup cake'}
];
// group the text for each com_id
var reducedList = list.reduce( ( elements, element ) => {
if ( !elements[ element.com_id ] ) {
elements[ element.com_id ] = { com_id: element.com_id, text: [] }
}
elements[ element.com_id ].text.push( element.text );
return elements;
}, {} );
console.log( reducedList );
// build the html
var newHTML = Object.values( reducedList ).map( element => {
return `<li>com_id:${ element.com_id }<span>${ element.text.join( '</span><span>' ) }</span></li>`;
} );
console.log( newHTML );

If you just want to build your HTML you can use Jquery $.each
var html = '';
$.each(list, function(i, el){
html += '<li>com_id:' + el.com_id + ' <span>' + el.text + '</span></li>';
});
$('#dynamic_const').html(html);

Related

html not appending to the carousel on popover

I Am Trying to make a popover with a bootstrap carousel and where the carousel items are to be generated and appended from a script but I get the carousel but I am unable to append the item. I tried hard but I didn't come up with a solution.
the HTML initialized is as below
HTML:
<div class="popup" data-popup="popup-1">
<div class="popup-inner">
<i class="fas fa-bars"></i>
<div class="frame">
<div id='carousel' class='carousel slide' data-bs-ride='carousel'>
<div class='carousel-inner items-slider1'>
</div>
</div>
</div>
</div>
</div>
the script I have tried was
Javascript:
function findallchord(currentchord , currenttype) {
for (let i = 1; i < 10; i++) {
if (Raphael.chord.find(currentchord ,currenttype,i)) {
Raphael.chord("div3", Raphael.chord.find(currentchord , currenttype,i), currentchord +' ' +currenttype).element.setSize(75, 75);
}
}
}
var getChordRoots = function (input) {
if (input.length > 1 && (input.charAt(1) == "b" || input.charAt(1) == "#"))
return input.substr(0, 2);
else
return input.substr(0, 1);
};
$('.popup').on('shown.bs.popover', function () {
$('.carousel-inner').carousel();
});
$('[data-bs-toggle="popover"]').popover({
html: true,
content: function() {
return $('.popup').html();
}}).click(function() {
var oldChord = jQuery(this).text();
var currentchord = getChordRoots(oldChord);
var currenttype = oldChord.substr(currentchord.length);
findallchord(currentchord , currenttype);
var chordsiblings = $('#div3').children().siblings("svg");
for (let i = 1; i < 10; i++) {
if (Raphael.chord.find(currentchord , currenttype,i)) {
var itemid = "chord" + i;
var theDiv = "<div class='carousel-item"+((itemid=="chord1") ? ' active':'')+" ' id='"+currentchord+''+itemid+"'> "+chordsiblings[i-1].outerHTML+" </div>";
$('.items-slider1').append(theDiv);
}
}
});
I have also tried appendTo also as
$(theDiv).appendTo('.items-slider1');
Please Help to solve this
This is the output I get, the appended elements are not in the carousel
Note: I am using Bootstrap 5
Try instantiating the carousel after you've set it up
/*
$('.popup').on('shown.bs.popover', function () {
$('.carousel-inner').carousel();
});
*/
$('[data-bs-toggle="popover"]').popover({
html: true,
content: function() {
return $('.popup').html();
}}).click(function() {
var oldChord = jQuery(this).text();
var currentchord = getChordRoots(oldChord);
var currenttype = oldChord.substr(currentchord.length);
findallchord(currentchord , currenttype);
var chordsiblings = $('#div3').children().siblings("svg");
for (let i = 1; i < 10; i++) {
if (Raphael.chord.find(currentchord , currenttype,i)) {
var itemid = "chord" + i;
var theDiv = "<div class='carousel-item"+((itemid=="chord1") ? ' active':'')+" ' id='"+currentchord+''+itemid+"'> "+chordsiblings[i-1].outerHTML+" </div>";
$('.items-slider1').append(theDiv);
}
}
$('.carousel-inner').carousel();
});
It was needed to do call the click function first before popover as below
$('[data-bs-toggle="popover"]').click(function() {
var oldChord = jQuery(this).text();
var currentchord = getChordRoots(oldChord);
var currenttype = oldChord.substr(currentchord.length);
findallchord(currentchord , currenttype);
var chordsiblings = $('#div3').children().siblings("svg");
for (let i = 1; i < 10; i++) {
if (Raphael.chord.find(currentchord , currenttype,i)) {
var itemid = "chord" + i;
var theDiv = "<div class='carousel-item"+((itemid=="chord1") ? ' active':'')+" ' id='"+currentchord+''+itemid+"'> "+chordsiblings[i-1].outerHTML+" </div>";
$('.items-slider1').append(theDiv);
}
}
}).popover({
html: true,
content: function() {
return $('.popup').html();
}});

JavaScript arrays adding last element instead of recently added input

Good evening. I am new to JavaScript and I need help with my mini-project and I have only one issue here and it is in the this.Add = function ().
It works properly when I enter a duplicate value from my list therefore it displays an alert that no dupes are allowed. But... when I enter a unique value, it only adds up the last element present (Wash the dishes) from myTasks list. instead of the one I recently entered and the list goes on adding the same ones. Did I just misplace something?
This is my final activity yet and I want to finish it to move to the next function. Thank you in advance.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Tasks CRUD</title>
<style>
#tasks{
display: none;
}
</style>
</head>
<body>
<center>
<form action="javascript:void(0);" method="POST" onsubmit="app.Add()">
<input type="text" id="add-task" placeholder="Add another card">
<input type="submit" value="Add">
</form>
<div id="tasks" role="aria-hidden">
<form action="javascript:void(0);" method="POST" id="saveEdit">
<input type="text" id="edit-task">
<input type="submit" value="Edit" /> <a onclick="CloseInput()" aria-label="Close">✖</a>
</form>
</div>
<p id="counter"></p>
<table>
<tr>
<th>Name</th>
</tr>
<tbody id="myTasks">
</tbody>
</table>
</center>
<script>
var app = new function() {
this.el = document.getElementById('myTasks');
this.myTasks = ['Clean the bathroom', 'Wash the dishes'];
this.Count = function(data) {
var el = document.getElementById('counter');
var name = 'task';
if (data) {
if (data > 1) {
name = 'Things To DO';
}
el.innerHTML = data + ' ' + name ;
} else {
el.innerHTML = 'No ' + name;
}
};
this.FetchAll = function() {
var data = '';
if (this.myTasks.length > 0) {
for (i = 0; i < this.myTasks.length; i++) {
data += '<tr>';
data += '<td>' + this.myTasks[i] + '</td>';
data += '<td><button onclick="app.Edit(' + i + ')">Edit</button></td>';
data += '<td><button onclick="app.Delete(' + i + ')">Delete</button></td>';
data += '</tr>';
}
}
this.Count(this.myTasks.length);
return this.el.innerHTML = data;
};
this.Add = function () {
el = document.getElementById('add-task');
// Get the value
var task = el.value;
if (task ) {
for(task of this.myTasks)
{
var ctr = 0;
if(document.getElementById("add-task").value == task){
ctr = 1;
break;
}
}
if(ctr == 1)
{
window.alert("Duplicates not allowed.");
}else{
// Add the new value
this.myTasks.push(task.trim());
// Reset input value
el.value = '';
// Dislay the new list
this.FetchAll();
}
}
};
this.Edit = function (item) {
var el = document.getElementById('edit-task');
// Display value in the field
el.value = this.myTasks[item];
// Display fields
document.getElementById('tasks').style.display = 'block';
self = this;
document.getElementById('saveEdit').onsubmit = function() {
// Get value
var task = el.value;
if (task) {
// Edit value
self.myTasks.splice(item, 1, task.trim());
// Display the new list
self.FetchAll();
// Hide fields
CloseInput();
}
}
};
this.Delete = function (item) {
// Delete the current row
this.myTasks.splice(item, 1);
// Display the new list
this.FetchAll();
};
}
app.FetchAll();
function CloseInput() {
document.getElementById('tasks').style.display = 'none';
}
</script>
</body>
</html>
In your for loop:
for (task of this.myTask) {
}
You are not declaring a new task variable, but instead assigning to the outer task variable, hence the repeated addition of tasks already in your list.
You can declare a new variable in the for scope like so:
for (const task of this.myTask) {
}
Your HTML as it is.
And your Javascript goes like below. You have a bug while checking if the task already exists in the array. As you're comparing string value either use simple for loop with triple equals or do as i have attached below.
var app = new function() {
this.el = document.getElementById('myTasks');
this.myTasks = ['Clean the bathroom', 'Wash the dishes'];
this.Count = function(data) {
var el = document.getElementById('counter');
var name = 'task';
if (data) {
if (data > 1) {
name = 'Things To DO';
}
el.innerHTML = data + ' ' + name ;
} else {
el.innerHTML = 'No ' + name;
}
};
this.FetchAll = function() {
var data = '';
if (this.myTasks.length > 0) {
for (i = 0; i < this.myTasks.length; i++) {
data += '<tr>';
data += '<td>' + this.myTasks[i] + '</td>';
data += '<td><button onclick="app.Edit(' + i + ')">Edit</button></td>';
data += '<td><button onclick="app.Delete(' + i + ')">Delete</button></td>';
data += '</tr>';
}
}
this.Count(this.myTasks.length);
console.log(this.myTasks.length);
return this.el.innerHTML = data;
};
this.Add = function () {
el = document.getElementById('add-task');
// Get the value
var task = el.value;
console.log(task);
if (task ){
var arrayContainsTask = (this.myTasks.indexOf(task) > -1);
if(arrayContainsTask == true){
window.alert("Duplicates not allowed.");
}else{
// Add the new value
this.myTasks.push(task);
// Reset input value
el.value = '';
}
// Dislay the new list
this.FetchAll();
}
}
}

Get start and end indices of multiple divs of a sentence in jQuery

I have an input text box which accepts sentences from the user and after accepting it from the user splits it using Regex and makes a div of each tokenized word and appends it into the table.
I want to enable clickable links, based on the div(s) I made in the earlier step, on the press of control key on the keyboard and left mouse click I want to select multiple div(s) like in this screenshot and consequently get the start and end indices of the selected word, and the word selected in that sentence.
Here is the code which I tried:
#{
ViewData["Title"] = "Index";
}
<style>
#editor {
padding: 5px;
border: solid green 1px;
}
</style>
<h2>AnnotationView</h2>
<h2>Enter text to annotate</h2>
<input type="text" id="myInput" />
<button id="btnAddUtterance" class="btn btn-info">Add Utterance</button>
<table id="tblText" class="table table-hover">
<thead>
<tr>
<th>Select</th>
<th>User Utterance</th>
</tr>
</thead>
<tbody></tbody>
</table>
<button id='btnDeleteRow' class='btn btn-danger'>Delete Utterance</button>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<!-- Latest compiled JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script>
$( function ()
{
$( '#btnAddUtterance' ).click( function ()
{
populateUtterance();
} );
function populateUtterance()
{
debugger;
let userUtterance = $( '#myInput' ).val();
let splittedUtterance = tokenizeUtterance( userUtterance );
let markup = "<tr><td><input type='checkbox' name='record'></td><td name = 'utterance'>" + splittedUtterance + "</td></tr>";
$( "#tblText tbody" ).append( markup );
$( '#myInput' ).val( '' );
}
$( "#myInput" ).keyup( function ( event )
{
if ( event.keyCode === 13 )
{
populateUtterance();
}
} );
function splitCharacters( utterance )
{
return utterance.split( '' );
}
function findSpacesIndex( utterance )
{
let index = 0;
let spacesIndex = [];
while ( ( index = utterance.indexOf( ' ', index + 1 ) ) > 0 )
{
spacesIndex.push( index );
}
return spacesIndex;
}
var lookUpObject = [];
function tokenizeUtterance( utterance )
{
debugger;
let spilittedUserText = utterance.toString().match( /[\w-']+|[^\w\s]+/g );
let div = '';
let wordStart = 0, wordEnd = 0;
let spacesIndex = [];
spacesIndex = findSpacesIndex( utterance );
let splittedUtteranceChars = [];
splittedUtteranceChars = splitCharacters( utterance );
$.each( spilittedUserText, function ( index, item )
{
div += '<div style="display: inline-block;margin:5px;" class="spilittedDiv">' + item + '</div>';
} );
console.log( lookUpObject );
return div;
}
$( document ).on( "click", "#tblText > tbody > tr > td:nth-child(2)", function ()
{
console.log( "Selected" );
} );
// Find and remove selected table rows
$( document ).on( 'click', '#btnDeleteRow', function ( e )
{
$( "#tblText tbody" ).find( 'input[name="record"]' ).each( function ()
{
if ( $( this ).is( ":checked" ) )
{
$( this ).parents( "tr" ).remove();
}
} );
} );
} );
</script>
Here's how it looks now:
An example would be user inputting an sentence like:
HELLO, WORLD which would give me an output of the sort on splitting of div(s).
<div>
<div> HELLO </div>
<div> , <div>
<div> WORLD </div>
</div>
for which I have written a function:
function tokenizeUtterance( utterance )
{
let spilittedUserText = utterance.toString().match( /[\w-']+|[^\w\s]+/g );
let div = '';
let wordStart = 0, wordEnd = 0;
let spacesIndex = [];
spacesIndex = findSpacesIndex( utterance );
let splittedUtteranceChars = [];
splittedUtteranceChars = splitCharacters( utterance );
$.each( spilittedUserText, function ( index, item )
{
div += '<div style="display: inline-block;margin:5px;" class="spilittedDiv">' + item + '</div>';
} );
return div;
}
So, if the user selects the div(s) which range from HELLO to WORLD, I should get an JSON object of the following sort:
{
"start": 0,
"end": 11,
"value": "HELLO, WORLD"
}
If the user selects the word HELLO and , I must get the JSON object like:
{
"start": 0,
"end": 5,
"value": "HELLO,"
}
Any help is appreciated, thank you.
I think HTML data-* Attributes can help you.
You just need to embed the start and end ndice of every word in the relative div in the tokenizeUtterance() function, I mean :
For the word Hello, the div would be like this :
<div style="display:inline-block;margin:5px;"
class="spilittedDiv"
id="divX"
data-start="0"
data-end="4"
data-value="Hello">Hello
</div>
So, to get the start, end and the value, you need to add this to your tokenizeUtterance():
var wordIndex = 0;
$.each( spilittedUserText, function ( index, item ){
divId = "div"+index;
divStart = wordIndex;
divEnd = wordIndex + item.length;
divValue = item;
div += '<div style="display:inline-block;margin:5px;"
class="spilittedDiv"
id="'+divId+'"
data-start="'+divStart+'"
data-end="'+divEnd+'"
data-value="'+divValue+'"
>' + item + '</div>';
wordIndex = wordIndex + item.length;
});
And after that, you can get these data using this :
var start = $("#divX").data("start");
var end = $("#divX").data("end");
var value = $("#divX").data("value");
If the user select the another div, you just set the var end to the second div data-end :
end = $("#div2").data("end");
value = value + $("#div2").data("value");

Get DOM path from a node to another

I need a method that, taken as parameters two nodes (node1 and node2), returns the minimum path that leads to node2 from node1.
Ideally, it returns an array of nodes, but for the moment it's OK to a string. So for example:
P
/ \
#text U
/ \
B I
| |
#text #text
function foo(node1, node2) {
...
}
when I run it in this way, for example on the nodes P (root) and B:
var res = foo(P, B);
console.log(res);
I obtain:
res = Array[3] {
0: P (class=..., id=...)
1: U (class=..., id=...)
2: B (class=..., id=...)
}
or, in the form of string:
res = "P(class=..., id=...) > U(class=..., id=...) > B(class=..., id=...)";
If the nodes have attributes (such as id or class), then returns even those (as in the example).
I searched the internet methods that did similar things but I found only methods that return the full path of the entire document and not between two nodes.
For example, I tried this method doesn't work for me because it returns the full path of a single node.
function getDomPath(el) {
var stack = [];
while ( el.parentNode != null ) {
console.log(el.nodeName);
var sibCount = 0;
var sibIndex = 0;
for ( var i = 0; i < el.parentNode.childNodes.length; i++ ) {
var sib = el.parentNode.childNodes[i];
if ( sib.nodeName == el.nodeName ) {
if ( sib === el ) {
sibIndex = sibCount;
}
sibCount++;
}
}
if ( el.hasAttribute('id') && el.id != '' ) {
stack.unshift(el.nodeName.toLowerCase() + '#' + el.id);
} else if ( sibCount > 1 ) {
stack.unshift(el.nodeName.toLowerCase() + ':eq(' + sibIndex + ')');
} else {
stack.unshift(el.nodeName.toLowerCase());
}
el = el.parentNode;
}
return stack.slice(1); // removes the html element
}
Another thing, I would use pure JavaScript, no jQuery.
I have no idea how to do what I need, a your help would be greatly appreciated.
Thank you
<!DOCTYPE html>
<html>
<script>
window.onload = function() {
console.log(min_path(
document.getElementById("4"),
document.getElementById("9")
));
};
function min_path(node1, node2) {
if(node1 === node2) {
return node1;
}
var node_1_ancestors = get_ancestors(node1);
var node_2_ancestors = get_ancestors(node2);
var divergent_index = 0;
while(node_1_ancestors[divergent_index] === node_2_ancestors[divergent_index]) {
divergent_index++;
}
var path = [];
for(var i = node_1_ancestors.length - 1; i >= divergent_index - 1; i--) {
path.push(node_1_ancestors[i]);
}
for(var i = divergent_index; i < node_2_ancestors.length; i++) {
path.push(node_2_ancestors[i]);
}
return path;
}
function get_ancestors(node) {
var ancestors = [node];
while(ancestors[0] !== null) {
ancestors.unshift(ancestors[0].parentElement);
}
return ancestors;
}
</script>
</head>
<body>
<div id="0">
<div id="1">
<div id="2">
<span id="3"></span>
<span id="4">node1</span>
</div>
<div id="5">
<p id="6"></p>
<span id="7">
<div id="8">
<div id="9">node2</div>
<div id="10"></div>
</div>
</span>
</div>
</div>
<div id="11"></div>
</div>
</body>
</html>
Edit: It was going in to an infinite loop when the nodes were equal, so I added a check for that.

javascript array to string conversion

I have this array in javascript:
[div.parts, div.editor, div.inside-1, div.container-2, div.inside-wrapper, div#content, div.whitebgpan, div, div#maindiv, body, html]
How can I convert it into string, so that the output will be:
div.parts div.editor div.inside-1 div.container-2 div.inside-wrapper div#content div.whitebgpan div div#maindiv body html
here is my code:
jQuery(document).on('click', function(e){
var ClickedParents = jQuery(e.target).parents(); //Get all parents of clicked element
var ClickedParents_array = jQuery.makeArray(ClickedParents); //Make array
console.log(ClickedParents_array); //Show output in colsole
});
You can use a combination of the jQuery each function and JavaScript's Array.Join function to solve this problem.
DEMO: http://jsfiddle.net/zay015ex/1/
I've artificially retrieved an array of jQuery objects to show how you can solve this, but the concept is common to your problem.
HTML
<div id="parent">
<div id="child1"></div>
<div id="child2"></div>
<div id="child3"></div>
<div id="child4"></div>
<div id="child5"></div>
</div>
JavaScript
var arrayOfObjects = $('#parent').children();
var ids = [];
$.each(arrayOfObjects, function(i, val)
{
ids.push(val.id);
});
var idString = ids.join(' ');
You can read up more on the jQuery each function here.
You can read up more on the JavaScript's Array.Join function
here.
===== Update =====
Ok, the following code is tested, just open a console and paste this. it selects all div tags and convert into selector string.
$.map($('div'),function toSelector(elem){
var jqObj = $(elem)
var tag = jqObj.prop('tagName').toLowerCase()
var classes = jqObj.attr('class') ? '.' + jqObj.attr('class').split(' ').join('.') : ''
var ids = jqObj.attr('id') ? '#' + jqObj.attr('id').split(' ').join('#'): ''
return tag + classes + ids
})
===================
Supposing they're jquery objects, you have to build the string manually.
For example, do something like following. (not tested)
function toSelector(jqObj){
var tag = jqObj.prop('tagName').toLowerCase()
var classes = jqObj.attr('class') ? '.' + jqObj.attr('class').split(' ').join('.') : ''
var ids = jqObj.attr('id') ? '#' + jqObj.attr('id').split(' ').join('#'): ''
return tag + classes + ids
}
array.map(toSelector)
I think below code is helpful for you.
<script type="text/javascript">
String.prototype.replaceAll = function ( token, newToken, ignoreCase ) {
var _token;
var str = this + "";
var i = -1;
if ( typeof token === "string" ) {
if ( ignoreCase ) {
_token = token.toLowerCase();
while( (
i = str.toLowerCase().indexOf(
token, i >= 0 ? i + newToken.length : 0
) ) !== -1
) {
str = str.substring( 0, i ) +
newToken +
str.substring( i + token.length );
}
} else {
return this.split( token ).join( newToken );
}
}
return str;
};
try{
var arr = [];
arr.push('div.parts', 'div.editor', 'div.inside-1', 'div.container-2', 'div.inside-wrapper', 'div#content', 'div.whitebgpan', 'div', 'div#maindiv', 'body', 'html');
var stringData = arr.toString();
stringData = stringData.replaceAll(",", " ");
console.log(stringData);
}catch(e){
alert(e)
}
</script>

Categories

Resources