How can I call a method with variable arguments from the On Click Event of a blazor html object in my Blazor server app? - razor

I can call from the OnClick event a method with arguments in my Blazor razor page. It is working.
for (var i = 0; i < Deltalogic.CNC_File_Array_lenght - 1; i++)
{
<tr>
<td #onclick="#(e => Read_CNC_Files("_N_MPF_DIR","_N_AUTO_MPF"))">#Deltalogic.CNC_File_Content</td>
</tr>
But if I write the arguments with variables, it is not working. Why?
for (var i = 0; i < Deltalogic.CNC_File_Array_lenght - 1; i++)
{
<tr>
<td #onclick="#(e => Read_CNC_Files(Deltalogic.Selected_CNC_File_name,Deltalogic.CNC_File_Content_Array[i]))">#Deltalogic.CNC_File_Content_Array[i]</td>
</tr>
}
I have validated that the variables have the same values, that I have written in example-1.

Related

Update scriptlets in HTML without reloading page

I am referring to this article about templated HTML and scriptlets with Google Apps Script:
https://developers.google.com/apps-script/guides/html/templates
It is written how to call an Apps Script function and load the data when loading the html page:
Code.gs:
function doGet() {
return HtmlService
.createTemplateFromFile('Index')
.evaluate();
}
function getData() {
return SpreadsheetApp
.openById('1234567890abcdefghijklmnopqrstuvwxyz')
.getActiveSheet()
.getDataRange()
.getValues();
}
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<? var data = getData(); ?>
<table>
<? for (var i = 0; i < data.length; i++) { ?>
<tr>
<? for (var j = 0; j < data[i].length; j++) { ?>
<td><?= data[i][j] ?></td>
<? } ?>
</tr>
<? } ?>
</table>
</body>
</html>
Question:
Is it possible to update the scriptlets without refreshing the whole page?
For example to implement a button and call the getData() function to load new data from the spreadsheet to the html?
Update:
I have adjusted the code with a simple button and a code to call the getData() function again and update the table. But of course doing it this way the for loop gets lost. Better would be to reload the whole code.
Is there a way to re-evaluate the whole page?
Any ideas?
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<button type="button" onclick="Refresh()">Refresh</button>
<? var data = getData(); ?>
<table id="datatable">
<? for (var i = 0; i < data.length; i++) { ?>
<tr>
<? for (var j = 0; j < data[i].length; j++) { ?>
<td><?= data[i][j] ?></td>
<? } ?>
</tr>
<? } ?>
</table>
</body>
<script>
function Refresh(){
google.script.run.withSuccessHandler(update).withUserObject(this).getData();
}
function update(returnValue){
document.getElementById("datatable").innerHTML= returnValue
}
</script>
</html>
If you will call getData() from the client-side, then you will need to build the table on the client-side. The easier way might be to create a string and then add it by using HtmlElement.outerHTML to replace the whole element or HtmlElement.innerHTML to replace the inner elements and content.
Client-side JavaScript code (put it between <script> tags, do not require to change your server-side code)
function refreshTable(){
google.script.run
.withSuccessHandler(updateTable)
.withFailureHandler((error) => console.error(error.message))
.getData()
}
function updateTable(data){
let html = '';
for (var i = 0; i < data.length; i++) {
html += `<tr>`;
for (var j = 0; j < data[i].length; j++) {
html += `<td>${data[i][j]}</td>`;
}
html += `</tr>`;
}
document.getElementById("datatable").innerHTML = html;
}
By the other hand, if you want to use Google Apps Script templated HTML to build the HTML table, then you need to call a function that evaluates the template to generate a HttpOutput object and then use HttpOutput.getContent() to return a string to the client side code, then you might pass this string to the corresponding element by using HtmlElement.innerHTML.
Server Side, in a .gs file
function includeFromTemplate(filename){
return HtmlService.createTemplateFromFile(filename).evaluate().getContent();
}
Server side, table.html file
<? var data = getData(); ?>
<? for (var i = 0; i < data.length; i++) { ?>
<tr>
<? for (var j = 0; j < data[i].length; j++) { ?>
<td><?= data[i][j] ?></td>
<? } ?>
</tr>
<? } ?>
Client Side. Call this function from onclick attribute or use the HtmlElement.addEventlistener method.
function refreshTable(){
google.script.run
.withSuccessHandler(html => {
document.querySelector('table').innerHTML = html;
})
.withFailureHandler((error) => console.error(error.message))
.includeFromTemplate('table')
}

How can I change with onclick event of a <td>the color of the td? The critical point is that the td elements are generated dynamically with code

In my Blazor server app, I am reading the CNC Files of a remote machine and listing them in the table's rows.
So far everything is OK.
When the user clicks on one TD element, the content of the CNC file will be shown on the screen in another table(This part I have not shown because it is not related to my problem)
I want that the last choosen CNC file (last clicked ) should be highlighted (font=red).
That means each time when the user selects another CNC-File, just the related should be higlighted all others should be in default color (black).
If I would have a static table I would use the a:focus. But my problem is that my td's will be generated dynamically. And I have to apply the a:focus function for just one td (that was clicked).
How can I do that?
I have tried to call a function in the style of the td style="#Style_CNC_File()" but the colors that I define in the function are applied to all of the td's.
Here is my code:
<table >
<tr>
<td>CNC Files</td>
</tr>
#{ if (Deltalogic.Return_Read_CNC_File == 0 && Deltalogic.Selected_CNC_File_Path_Type == "file")
{
for (var i = 0; i < Deltalogic.CNC_File_Array_lenght_dir - 1; i++)
{
var arg0 = "abc";
var arg1 = "def";
var arg2 = "ghi";
<tr >
<td style="#Style_CNC_File()" #onclick='#(e => Read_CNC_Files(arg0,arg1,arg2))'>/#Deltalogic.CNC_File_Out_Array_dir[i]</td>
</tr>
}
}
}
</table>
In my razor.cs file:
public string Style_CNC_File()
{
if (var_clicked == true)
{
return "color:#FF0000";
}
else
{
return "color:#000000";
}
}
Maybe you can set an id to your td and store the selected id :
<tr>
<td>CNC Files</td>
</tr>
#{ if (Deltalogic.Return_Read_CNC_File == 0 && Deltalogic.Selected_CNC_File_Path_Type == "file")
{
for (var i = 0; i < Deltalogic.CNC_File_Array_lenght_dir - 1; i++)
{
var arg0 = "abc";
var arg1 = "def";
var arg2 = "ghi";
<tr >
<td #onclick='#(e => HandleClick(i, arg0,arg1,arg2))' style="#Getstyle(i)">/#Deltalogic.CNC_File_Out_Array_dir[i]</td>
</tr>
}
}
}
</table>
#code {
int selectedId = -1;
void HandleClick(int id, string args0, string args1, string args2)
{
selectedId = i;
Read_CNC_Files(arg0,arg1,arg2);
}
void Getstyle(int id)
{
if (selectedId == i)
return "background-color:red;";
return string.Empty;
}
}
You can change the class or style as you want according to the index of the line.

Is using a variable on HTMLElement.style.variable in Angular/TypeScript possible?

I try to implement an updateStyle(...)-method inside of an Angular-Component.
With this method specific elements with unique id's shall be styled.
Following code-snippet leads to:
Property 'variable' does not exist on type 'CSSStyleDeclaration'.
Is it possible to make angular compile anyway, so the variable is filled with a legit value in runtime or do I have to implement the method for every style-declaration, that I am going to use the method on?
updateStyle(id, variable, value){
var components = document.querySelectorAll("[id]") as NodeListOf<HTMLElement>;
for(var i = 0; i < components.length; i++) {
if(components[i].getAttribute("id") == id) {
components[i].style.variable = value;
}}}
You can put variable in square brackets like this:
updateStyle(id, variable, value) {
var components = document.querySelectorAll("[id]") as NodeListOf<HTMLElement>;
for (var i = 0; i < components.length; i++) {
if (components[i].getAttribute("id") == id) {
***components[i].style[variable] = value;***
}
}
}

Splitting foreach in a table

As of right now my table looks like this:
But I want to split the foreach to have it look something like this
Is possible to do this?
And this is the foreach:
#foreach (var date in ViewBag.MissingDays)
{
var isoDate = date.ToString("yy-MM-dd");
<tr>
<td>
#isoDate
</td>
</tr>
}
You can use the following code to generate rows containing 9 columns
#{var counter = 1; }
<tr>
#foreach (var date in ViewBag.MissingDays)
{
var isoDate = date.ToString("yy-MM-dd");
<td>#isoDate</td>
if (counter % 9 == 0)
{
#:</tr><tr> // end current row and begin new one
}
counter++;
}
</tr>

Google App Script parse table from messed html

I want to create a script which download html, parse a table and save it to a SpreadSheet. I am stuck on downloading and parsing.
Xpath to table is:
/html/body/table/tbody/tr[5]/td/table/tbody/tr/td[2]/table
Currently I am stuck at parsing Xpath.
function fetchIt() {
var fetchString="http://www.zbranebrymova.com/index.php?s_lev=22&type=nabku*signa"
var response = UrlFetchApp.fetch(fetchString);
var xmlDoc = Xml.parse(response.getBlob().getDataAsString(),true);
var b = xmlDoc.getElement().getElement("body").getElement("table") ;
Logger.log(b);
}
I don't know if this will be helpful, here is a snippet of my table parsing code:
html file FOO.HTM:
<html>
<head> </head>
<body style="margin-left:10px">
<table title="">
<tbody>
<tr>
<th align="center" abbr="Sunday">Sun</th>
<th align="center" abbr="Monday">Mon</th>
</tr>
<tr>
<td align="left"><a title="January 01">1</a>
<div>Joe,Doe</div>
<div>Murphy,Jack</div>
</td>
<td align="left"><a title="January 02">2</a>
<div>Carlson,Carl</div>
<div>Guy,Girl</div>
<div>Lenin,Vladimir</div>
</td>
</tr>
</tbody>
</table>
</body>
<html>
and this is how I parse it:
function foo() {
var page = UrlFetchApp.fetch('foo.htm');
var rows = Xml.parse(page,true).getElement()
.getElement("html")
.getElement("body")
.getElement("table")
.getElement("tbody")
.getElements("tr");
for (var ii = 0; ii < rows.length; ii++) {
var cols = rows[ii].getElements("td");
for (var jj = 0; jj < cols.length; jj++) {
var divs = cols[jj].getElements("div");
for (var kk = 0; kk < divs.length; kk++) {
var div = divs[kk];
}
}
}
}
cheers, sean