I have this JSON from which I need to create a table. This table must be a legend for a webmap created with OpenLayers 6. As you have seen the JSON comes from Geoserver.
Below my code:
let updateLegend = function(resolution) {
let graphicUrl = strutturale_puc.getSource().getLegendUrl(
resolution,
{'FORMAT': 'application/json'}
);
if(graphicUrl) {
fetch(graphicUrl)
.then(function (response) {
return response.text();
})
.then(function (data) {
const jsonData = JSON.parse(data);
const legendData = jsonData.Legend[0].rules;
const table = document.getElementById("table");
const footer = table.createTFoot();
legendData.forEach((value) => {
cellStroke = value.symbolizers[0].Polygon.stroke;
cellFill = value.symbolizers[0].Polygon.fill;
cellContent = value.name;
const tableRaw = footer.insertRow(value);
tableRaw.insertCell(0).innerHTML = '<td style="border: 4px solid ' + cellStroke + '; background-color: ' + cellFill + '; max-width: 10px;"></td>';
tableRaw.insertCell(1).innerHTML = '<td style="border: none;">' + cellContent + '</td>';
console.log(tableRaw);
});
}).catch((error) => {
console.error(error)
});
}
The table is inside a div:
<div class="" id="legend">
<table class="table" id="table">
</table>
</div>
My problem is that I can't see any style when the table is created, I can see only the text(cellContent). For me is strange because if I use this:
<div class="">
<table>
<tr>
<td style="border: 4px solid #791919; background-color: #A71C1C; max-width: 10px;"></td>
<td style="border: none;">Item</td>
</tr>
</table>
</div>
I can see all correctly. What I wrong?
.insertCell creates a <td> element, inserts it into the table, and returns a reference to it (per the spec).
You then set the contents of that <td> to contain another <td> where you add the styling rule.
So now you essentially have:
<td>
<td style="border: 4px solid #791919; background-color: #A71C1C; max-width: 10px;"></td>
</td>
You can only have a <td> tag within a <tr> tag, so the browser removes the internal <td> tag (along with its styling), and adds its contents to the original <td>.
To solve the issue, you need to add the styling to the <td> that it makes for you. For example:
let firstCell = tableRaw.insertCell(0);
firstCell.setAttribute("style", 'border: 4px solid ' + cellStroke + '; background-color: ' + cellFill + '; max-width: 10px;');
firstCell.innerHTML = "";
Code quality notes:
You should use CSS classes rather that inline styles.
You should use template literals rather than inline string concatenation.
Related
I'm new to Javascript and learn about querySelector(), createElement(), setAttribute and loop.
I try to create a table with a row, which contains 5 cells in it.
Imagine I create in HTML file. I use following code to execute my idea:
// 1. select id = pixelCanvas and store in var table.
const table = document.querySelector('#pixelCanvas');
// 2. create table row element <tr></tr> and append to var table.
table.appendChild(document.createElement('tr'));
// 3. create element table data and store in var data.
const data = document.createElement('td');
// 4. set html attribute with class="cell", width: 20px & height: 20px for table data
data.setAttribute('style', 'width: 20px; height: 20px:');
// 5. use for loop and appendChild() to append 5 <td></td> to <tr></tr>
for (i = 0; i < 5; i++) {
let tblRow = document.querySelector('tr');
tblRow.appendChild(data);
};
Here is the result in HTML page.
Obviously my idea doesn't work as expected. Appreciate your advice: where goes wrong?
prefer to use css to style attributes.
there is also js methods for tables :
HTMLTableElement.insertRow()
HTMLTableRowElement.insertCell()
const myTable = document.querySelector('table#pixelCanvas')
for (let r=0;r<5;++r) {
let row = myTable.insertRow()
for (c=0;c<5;++c) {
row.insertCell().textContent = `${r}.${c}`
}
}
table#pixelCanvas {
border-collapse: collapse;
font-size: 9px;
}
table#pixelCanvas td {
padding: 5px;
width: 20px;
height: 20px;
border: 1px solid black;
}
<table id="pixelCanvas"></table>
Your code is very close to working - you just need to create a seperate td element for each iteration of the for loop, and setting the style attribute is much easier when done via the .style property of the element.
Also instead of trying to query for the row you have just created, you can use the return value of the createElement function - it will give you the variable containing the new element.
See this snippet:
const table = document.querySelector('#pixelCanvas');
const colors = ["red", "orange", "green", "blue", "purple"];
const row = document.createElement('tr');
table.appendChild(row);
for (i = 0; i < 5; i++) {
const cell = document.createElement('td');
cell.style.width = "20px";
cell.style.height = "20px";
cell.style.backgroundColor = colors[i];
row.appendChild(cell);
};
<table id="pixelCanvas"></table>
You mean this
Move the row outside the loop and if you need the cells to be the same, clone the one you made - you also had a typo in it (colon instead of semicolon)
I would also target the tbody since a table should have such a thing
const table = document.querySelector('#pixelCanvas tbody');
const data = document.createElement('td');
data.setAttribute('style', 'width: 20px; height: 20px;');
let tblRow = document.createElement('tr');
for (let i = 0; i < 5; i++) {
let cell = data.cloneNode(true)
cell.textContent = i;
tblRow.appendChild(cell);
}
table.appendChild(tblRow);
<table id="pixelCanvas">
<thead>
</thead>
<tbody>
</tbody>
</table>
Result
<table id="pixelCanvas">
<thead>
</thead>
<tbody>
<tr>
<td style="width: 20px; height: 20px;">0</td>
<td style="width: 20px; height: 20px;">1</td>
<td style="width: 20px; height: 20px;">2</td>
<td style="width: 20px; height: 20px;">3</td>
<td style="width: 20px; height: 20px;">4</td>
</tr>
</tbody>
</table>
I have 'td' element in this object how to get parent element value by class name?
console.log($this.parent().html())
show in console:
<td class="nr"><div contenteditable="true">7</div></td><td class="abc"><div contenteditable="true">A</div></td><td class="nazwa"><div contenteditable="true" class="xyz">logic lvl convert</div></td><td class="opis">3.3V to 5V</td><td class="symbol"> </td><td class="ilosc">6</td><td class="nowy">TAK</td><td class="ds"></td>
I try to find how to get value from td with specified class but after long time spended on gogle I don't know how to do that :/
I need to get value elements with class #nr, #abc and #ds
If you are wanting to manually get the values of .nr, .abc and .ds..
var trJqObject = $('tr');
$('.clicker.string').click(function() {
var theValuesAsString; // will be a string
var separator = ', ';
theValuesAsString = $('.nr div', trJqObject).text() + separator;
theValuesAsString += $('.abc div', trJqObject).text() + separator;
theValuesAsString += $('.ds', trJqObject).text();
alert(theValuesAsString);
})
$('.clicker.array').click(function() {
var theValuesAsArray = []; // will be an array
theValuesAsArray.push($('.nr div', trJqObject).text());
theValuesAsArray.push($('.abc div', trJqObject).text());
theValuesAsArray.push($('.ds', trJqObject).text());
$.each(theValuesAsArray, function() {
alert(this);
})
})
.clicker {
position: fixed;
bottom: 0;
padding: 2px 6px 1px 6px;
background-color: hsla(188, 100%, 50%, 1);
cursor: pointer;
}
.clicker:hover {
background-color: hsla(287, 100%, 72%, 1);
}
.clicker.string {
left: 0;
}
.clicker.array {
right: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td class="nr">
<div contenteditable="true">7</div>
</td>
<td class="abc">
<div contenteditable="true">A</div>
</td>
<td class="nazwa">
<div contenteditable="true" class="xyz">logic lvl convert</div>
</td>
<td class="opis">3.3V to 5V</td>
<td class="symbol"></td>
<td class="ilosc">6</td>
<td class="nowy">TAK</td>
<td class="ds">empty</td>
</tr>
</table>
<div class="clicker string">click to show values as string</div>
<div class="clicker array">click to loop values array</div>
If you reply to this question with more information about what you want to get and what you want to do with it and I'll update this fiddle.
fiddle
https://jsfiddle.net/Hastig/4uakr7mn/
I display the list of files, (in a database), that I could download in a table.
<table style="border: none; width:100%">
#for (int i = 0; i <= Model.docs.Count() - 1; i++)
{
<tr onclick="downloadFile('#Model.docs[i].id.ToString()')" class="rowFile" data-row=#i id=#("rigaDoc" + i)>
<td style="border-bottom:1px solid black; width:30px;">
<img src="#Url.Content(Model.docs[i].icon)" alt="Image" />
</td>
<td style="border-bottom:1px solid black; padding-left: 20px; width:auto;">
#Html.Label(Model.docs[i].nameFile.ToString().Split('.')[0], new { #class = "" })
</td>
</tr>
}
</table>
Once the user clicks on a row of that table, I need to send to the controller the GUID of that row and start the file download.
function downloadFile(fileId) {
var urlDownload = '#Url.Action("Download", "GestioneDocumenti", new { id = fileId })';
}
However, I cannot use fileId because debugger says:
"the name fileId is not used in this context".
How can I send the information to the controller method?
Razor is server side code and is parsed on the server before it is sent to the view. Change your function to
function downloadFile(fileId) {
var urlDownload = '#Url.Action("Download", "GestioneDocumenti")' + '/' + fileId;
}
A better solution would be to generate the url as a data- attribute
<tr data-url="#Url.Action("Download", "GestioneDocumenti", new { id = Model.docs[i].id })" class="rowFile">
and change the script to
$('.rowFile').click(function() {
var urlDownload = $(this).data('url');
});
I am using JavaScript to insert elements inside a container div:
<tr>
<td align="left">
</td>
<td style="background-color:#5D7B9D">
<div id="headerMasterDiv">
</div>
</td>
<td style="width: 18px; height: 18px;">
</td>
</tr>
for (var i=0; i < len; i++ )
{
id = "headerColumn_" + i.toString();
width = columnWidths[i];
text = columnTexts[i];
html = " <div id=\""+id+"\" class=\"test\">"+text+"</div> ";
header.innerHTML += html;
}
However I would like the inner to overflow, so I can activate an horizontal scrollbar. But instead they are wrapping:
Tx.
Just add the overflow:auto to your div.
In the test class :
.test
{
overflow:auto;
}
Or inline style, i suggest using quot and double quot it's more readable :
' <div id="'+id+'" class="test" style="overflow:auto">'+text+'</div> ';
Scenario:
I have a results table with a checkbox, when the checkbox is checked, the content of the row(actually 2 columns concateneted only, are copied to a new div, with the job code and job name). This works pretty well, and I am avoiding duplicated already.
However, in the new results div, I am creating an anchor tag to remove the div itself.
After the div has been removed, I should be able to add the selected job again with the checkbox.
Please note that there are many jobs in the results table, so putting the flag to false again will not work.
Also if you find a better title for this question, please let me know
//On every checkbow that is clicked
var flag = false;
$("#ctl00_PlaceHolderMain_myGrid input").change(function () {
if (this.checked && flag === false) {
flag = true;
var jobCode = $(this).parent().parent().parent().find("td:eq(2)").text()
var jobName = $(this).parent().parent().parent().find("td:eq(1)").text()
var displayvalue = jobCode.toUpperCase() + " - " + jobName.toUpperCase();
AddSelectedJob(jobCode, displayvalue);
//$(this).unbind('change'); //Unbind the change event so that it doesnt fire again
FillSelectedJobs();
}
});
//Add selected job in the results div
function AddSelectedJob(id, display) {
//create a div for every selected job
$("[id$=ResultsDiv]").append('<div class="selectedjobs" id=' + id + '>' + display + 'Remove selected job</div>');
}
//Removes the selected job from the resutls div
function removeSelectedJob(el) {
$(el).parent().remove();
}
The generated html is like this:
<div>
<div style="height: 300px; overflow: auto; float: left">
<div>
<table cellspacing="0" cellpadding="4" id="ctl00_PlaceHolderMain_myGrid" style="color:#333333;width:100%;border-collapse:collapse;">
<tr style="color:White;background-color:#5D7B9D;font-weight:bold;">
<th scope="col"> </th><th scope="col">JobCode</th><th scope="col">JobName</th><th scope="col">JobPartner</th><th scope="col">JobManager</th><th scope="col">ClientName</th>
</tr><tr style="color:#333333;background-color:#F7F6F3;">
<td>
<input id="ctl00_PlaceHolderMain_myGrid_ctl02_CheckBox1" type="checkbox" name="ctl00$PlaceHolderMain$myGrid$ctl02$CheckBox1" />
</td><td>jobcode01</td><td>jobname</td><td>xx</td><td>xx</td><td>xx</td>
</tr>
</table>
</div>
</div>
<div style="margin-top: 0px; margin-left: 10px; float: left">
<span>Selected :</span>
<div id="ResultsDiv" style="margin-top: 0px">
</div>
</div>
Firstly I suggest some changes to your HTML. Separate out the styles from your DOM and place them in classes.
This makes sure there is separation of concerns
HTML
<div>
<div class="divMain">
<div>
<table cellspacing="0" cellpadding="4"
id="ctl00_PlaceHolderMain_myGrid" class="table">
<tr class="rowHead">
<th scope="col"> </th>
<th scope="col">JobCode</th>
<th scope="col">JobName</th>
<th scope="col">JobPartner</th>
<th scope="col">JobManager</th>
<th scope="col">ClientName</th>
</tr>
<tr class="row">
<td>
<input id="ctl00_PlaceHolderMain_myGrid_ctl02_CheckBox1"
type="checkbox"
name="ctl00$PlaceHolderMain$myGrid$ctl02$CheckBox1"
data-flag="false" />
</td>
<td>column1</td>
<td>column2</td>
<td>column3</td>
<td>column4</td>
<td>column5</td>
</tr>
</table>
</div>
</div>
<div class="m0 selected">
<span>Selected :</span>
<div id="ResultsDiv" class="m0"></div>
</div>
CSS
.divMain{
height: 300px;
overflow: auto;
float: left
}
.table{
color:#333333;
width:100%;
border-collapse:collapse;
}
.rowHead{
color:White;
background-color:#5D7B9D;
font-weight:bold;
}
.row{
color:#333333;
background-color:#F7F6F3;
}
.m0{
margin-top: 0px;
}
.selected{
margin-left: 10px;
float: left
}
Javascript
$("#ctl00_PlaceHolderMain_myGrid input").change(function () {
// Next cache your selector
// so that you need not crawl the DOM multiple times
var $this = $(this),
$row = $this.closest('.row'),
currFlag = Boolean($this.data('flag'));
// As there might be multiple jobs , a single flag variable
// will not work. So you can set a data-flag attribute on the
// input that stores the current value
if (currFlag === false && this.checked) {
// Set the corresponding flag to true
$this.data('flag', true);
var jobCode = $row.find("td:eq(2)").text(),
jobName = $row.find("td:eq(1)").text(),
displayvalue = jobCode.toUpperCase() + " - "
+ jobName.toUpperCase(),
inputId = $this.attr('id')
// Pass the input name too as you need to set the value of
// the corresponding flag value again as you can add it multiple times
AddSelectedJob(jobCode, displayvalue, inputId);
FillSelectedJobs();
}
});
//Add selected job in the results div
function AddSelectedJob(id, display, inputId) {
//create a div for every selected job
// Use the inputId to save it as a data-id attribute
// on anchor so that you can set the value of the flag after
// removing it
var html = '<div class="selectedjobs" id=' + id + '>' + display ;
html += '<a href="javascript" data-id="'+ inputId
+'">Remove selected job</a></div>';
$('[id$=ResultsDiv]').append(html);
}
// Remove the inline click event for the anchor and delgate it to the
// static parent container
$('[id$=ResultsDiv]').on('click', 'a', function(e) {
var $this = $(this),
$currentCheckbox = $this.data('id');
// Set the flag value of the input back to false
$('#'+ $currentCheckbox).data('flag', false);
e.preventDefault(); // prevent the default action of the anchor
$this.closest('.selectedjobs').remove();
});
function FillSelectedJobs() {
//save values into the hidden field
var selectedJobs = $("[id$=ResultsDiv]").find("[class$='selectedjobs']");
var returnvalue = "";
for (var i = 0; i < selectedJobs.length; i++)
returnvalue += selectedJobs[i].id + ";";
$("[id$=HiddenClientCode]").val(returnvalue);
}
Check Fiddle