Angular Navigation Blocking HTML Rendering When `navigateByUrl` is Used, But Allows Typescript Code to Run

I’m working with Angular and I’m having an issue where my page succesfullPayment doesn’t load HTML document, but allows the typescript of the component to run. Let’s start with my component ts:

import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';


@Component({
  selector: 'app-succesfull-payment',
  standalone: true,
  imports: [FormsModule, CommonModule],
  templateUrl: './succesfull-payment.component.html',
  styleUrl: './succesfull-payment.component.css'
})
export class SuccesfullPaymentComponent implements OnInit{

  token! : any;
  payerId!: any;
  orderId!: any;

  constructor(private route: ActivatedRoute, private router: Router, private http: 
HttpClient) {}

  ngOnInit(): void {

    console.log("successfully paym,ent page loaded!!!!");

    this.route.queryParams.subscribe(params => {
      this.token = params['token'];
      this.payerId = params['payerId'];
      this.orderId = params['orderId'];
  
      console.log(`paymentId aka token: ${this.token}`);
      console.log(`orderId: ${this.orderId}`);

      if(this.token && this.orderId){
        console.log(`paymentId aka token: ${this.token}`);
        console.log(`orderId: ${this.orderId}`);
        console.log('about to send capture payment request');
        this.http.post(`http://localhost:3000/capturePayment`, {token: this.token, orderId: this.orderId})
        .subscribe({
          next:(data: any)=>{
            if (data.success){
              console.log(` ${data.message}`);

              this.router.navigateByUrl('/dashboard'); //this line prevents successfull-payment from rendering its html doc

            } else{
              alert(data.message);
            }
          },error : (error: any) =>{
            console.error('error: ', error);
          }
        }); 
        console.log('sent capture payment request successfully'); 
      }
  

    });}}

What the issue most likely is:
I think what is happening is that the this.router.navigateByUrl('/dashboard'); is trigerring before the current html doc is fully loaded, causing angular to trigger another reroute before current one is fully through, to overcome this I have attempted the following:

1- Setting a setTimeout function:
I have attempted giving the successfullpayment component 30 seconds before trigerring the reroute to allow enough time for html to load and for user to read the page components, however that did not work.

2- Setting an isLoaded variable and making it an observable so that the redirect line will only trigger if isLoaded is switched to true, but the same issue still occurred.

Important Notes

1- Both of the attempted solutions above worked fine when I commented out the this.router.navigateByUrl('/dashboard'); so I am really not sure why this particular line is giving angular so much trouble!

2- Although the html doc is not loaded, the typescript code is executed, and it has the desired effect in the backend. The problem is that it gives an error on the front end and does not even allow for redirection to '/dashboard'

Questions

1- Why does the page rendering break when I trigger the router navigation after completing the HTTP request?

2- How can I ensure that the page renders properly before navigating away?

Any help would be greatly appreciated!

Need help in next js 15 middleware to attach the userId and username with req body

I created a middleware using NextJS 15. I am able to decode the token successfully and got userId and username and i wanted to attach it with req body object so once the todo created by a user it should add the userId and username as well inside the a todo

For example: 
{
    "message": "A New Todo created successfully",
    "newTodo": {
        "title": "Learn Sundarkand",
        "status": false,
        "date": "2025-01-20T06:58:20.469Z",
        "_id": "678df40c9668b2d9b71c8f99",
        "userId" : "678df40c9668b2d9b71c8",
        "userName" : "xyz",
        "__v": 0
    }
}

this is my middlware code snippet kindly help me asap… thankyou

export async function middleware(req) {
  console.log("------>Middleware triggered");
  try {
    const token = await getCookies("jwtToken");

    if (!token) {
      return NextResponse.json(
        { message: "Unauthorized Access" },
        { status: 401 }
      ).redirect(new URL("/login", request.url)); // --- what should i add in request.url ? Find out here
    }

    // verify token using jose
    const {
      payload: { userId, username },
    } = await jwtVerify(
      token,
      new TextEncoder().encode(process.env.JWT_SECRET)
    );

    console.log("Decoded Token:", username, userId);
    // console.log("Request", request);
    // attach with the request object ---- > TEST this on tomorrow.
    const body = await req.json();
    body.userId = userId;
    body.username = username;

    console.log("REq---->", body);
    return NextResponse.json({ body }).next();
  } catch (error) {
    return NextResponse.json({ message: error.message }, { status: 500 });
  }
}

// See "Matching Paths" below to learn more
export const config = {
  matcher: ["/todos/create"],
};

mark telegram message as read using js in console

i have a request from client to read messages from telegram web page (scrapper) and send them to the other telegram chat. i have created the parser and all other parts.
even added the scrolling. but telegram does not mark messages as read during the scrolling and as result it jump back to the first “unread” message. as result scrapper dont work
i include my script directly in browser console

function scrollChatToBottom() {
const element = document.querySelector('.MessageList');
if (element) {
    element.scrollTop = element.scrollHeight;
}
}

this code works for the first 10 messages. and then stop working, because new messages not inserting into the DOM, because there are “unread” messages

Why is my manual event trigger not working in dynamically generated form inputs?

I am working on a project that dynamically generates form inputs, which are added to a wrapper around my form. I researched this problem and found a solution involving new Event('change', { bubbles: true }), but it didn’t work for me. I also tried manually triggering the onchange event for the form wrapper, like this, but that also didn’t work.

Here is the part of my code where the input is generated:

get image() {
  return {
    emoji: {
      key: "Arxa fon şəkili (emoji)",
      typeof: "component",
      render: "string",
      component: createElement(
        "div",
        {
          title: "Arxa fon şəklini emojidən seç",
          width: "100%",
        },
        createElement(TextField, {
          id: "selectEmoji",
          name: "options.plugins.image.emoji",
          size: "small",
        }),
        createElement(EmojiPicker, {
          width: "100%",
          onEmojiClick: (emoji, event) => {
            const el =
              event.target.ownerDocument.playgroundForm.querySelector(
                "#selectEmoji"
              );
            el.value += emoji.emoji;
            el.focus();
            el.dispatchEvent(
              new Event("input", {
                bubbles: true,
                cancelable: false,
              })
            );
          },
        })
      ),
      data: this.options?.plugins?.image?.emoji,
    },
    position: this.position(this.options?.plugins?.image?.position),
  };
}

All inputs are dynamically added inside this wrapper:

  <Box
    name="playgroundForm"
    component="form"
    onChange={updateOption}
  >
    <Playground
      current={store.current}
      chart={store.charts[store.current]}
      dispatch={dispatch}
    />
  </Box>

And here is the updateOption method used to change the state:

  const updateOption = (e) => {
    const updatedObj = { ...store.charts[store.current].options };
    let value = "";

    if (e.target.hasOwnProperty("checked")) {
      value = e.target.checked;
    } else {
      value = e.target.value;
    }

    set(updatedObj, e.target.name, value);

    dispatch({
      type: "EDIT_CHART",
      payload: {
        changed: {
          key: e.target.name,
          val: value,
        },
        options: updatedObj,
      },
    });
  };

Can anyone explain why the manual trigger isn’t working, or suggest an alternative way to achieve this?

Open zapier chatbot on “Contact Us” button click also

I am using zapier chatbot and below is the embed code of the chatbot

<script async type='module' src='https://interfaces.zapier.com/assets/web-components/zapier-interfaces/zapier-interfaces.esm.js'></script>
<zapier-interfaces-chatbot-embed is-popup='true' chatbot-id='*****************'></zapier-interfaces-chatbot-embed>

Using this code, I see the chat icon at the bottom right; it works fine when we click on it(having iframe structure).

Now I have a Contact Us button in the header and when I click on the Contact Us button, I want to open the chatbot automatically

How can I do this?

Issue with CSV Download Functionality When Filename Contains a Dot

I’m implementing a feature in my web application to download CSV files, but I’ve encountered an issue where the file extension displays as “.bb” instead of “.csv” when the filename includes a dot. Here is the code snippet I’m using:

const csvData = new Blob(  
  [[].map(row => row.join(",")).join("n")],  
  { type: "text/csv;charset=utf-8;" }  
);  
const link = document.createElement("a");  
link.href = window.URL.createObjectURL(csvData);  
link.download = "aa.bb";  
link.click(); 

I know I can change link.download = "aa.bb.csv" to include the correct file extension, but are there any other solutions to fix this issue?

Jquery animate does not work on window object

I’m using $(window).animate(attributes, options) to handle animations, where I pass scrollTop and scrollLeft values in the attributes, and additional options like axis, duration, and offset in the options. This setup works perfectly in Chrome and Edge, but it fails in Safari. From my observations, the animation functions correctly when the element is set to 'html, body', but it does not work when the target is window. Any ideas why its not working on window.

Tried ('html, body').animate(attributes, options) works well on safari and chrome.

How is this seemingly airtight synchronous SharedArrayBuffer setup manifesting corruption?

I have a setup where I have a couple dozen web workers postMessage requests to the main thread and then synchronously block for the response:
enter image description here

Since this is synchronous, the web worker never makes a postMessage request until it has successfully extracted the response from the shared array buffer. However, what I’m observing is that very rarely (after thousands of messages), the SharedArrayBuffer has a corrupted response in it. I was able to exacerbate the problem so it happens pretty frequently with this 90-line reproducible example:

//////////////////// WORKER
function workerFn() {
    const sab = new SharedArrayBuffer(1024 * 1024) // [0:4 Atomics.wait signal][4:8 data length][8:8+data length JSON data]
    const vi32 = new Int32Array(sab); // View needed for Atomics.wait
    const vui8 = new Uint8Array(sab); // View needed for TextDecoder
    const sbuf = { sab, vi32, vui8 };
    postMessage({ type: "sab", sab });

    let pl = 0;
    while (true) {
        postMessage({ type: "sync", payload: pl++ });

        let tdec = new TextDecoder();

        let data = "";
        let data_length;
        
        // This ostensibly synchronously blocks until the first int32 of the SharedArrayBuffer changes
        // The main thread is responsible for changing this value and calling Atomics.notify()
        Atomics.wait(sbuf.vi32, 0, 0); // Wait for expected value to change
        data_length = sbuf.vi32[1];

        // The data is JSON as utf-8 encoded uint8
        data += tdec.decode(sbuf.vui8.slice(8, 8 + data_length)); // 8 byte offset for header

        // Reset expected value to 0 since if we've made it this far, then it is non-zero
        Atomics.store(sbuf.vi32, 0, 0);

        let m;
        try {
            m = JSON.parse(data);
        } catch (e) {
            // !! THIS SHOULD NEVER HAPPEN, YET IT DOES
            throw new Error("How is this possible? Bad JSON:" + data);
        }

        if (m.cooldown > 0) {
            // Since this should never change until the next postMessage, we should be able to wait on it
            Atomics.wait(sbuf.vi32, 0, 0, m.cooldown);
        }
    }
}

//////////////////// MAIN THREAD
let processedMessages = 0;
function onWorkerMessage(workerName, data) {
    if (data.type === 'sab') {
        console.log('Received SAB from', workerName)
        workers[workerName].sbuf = {
            sab: data.sab,
            vi32: new Int32Array(data.sab), // View needed for Atomics.store
            vui8: new Uint8Array(data.sab), // View needed for TextEncoder
        };
    } else if (data.type === 'sync') {
        processedMessages++;
        if (processedMessages % 10000 === 0) {
            console.log('Processed', processedMessages, 'messages')
        }

        // Do a little fake work
        for (let i = 0; i < 100; i++) {
            Math.random();
        }

        // Send a message back to the worker
        let m = { rv: data.payload % 2 === 0, cooldown: data.payload % 2 === 0 ? 0 : 0.5 };
        const rui8 = new TextEncoder().encode(JSON.stringify(m));
        const sbuf = workers[workerName].sbuf;

        sbuf.vi32[1] = rui8.length;
        sbuf.vui8.set(rui8, 8);

        // Signal the worker that the data is ready
        Atomics.store(sbuf.vi32, 0, 1);
        Atomics.notify(sbuf.vi32, 0);
    }
}

//////////////////// INIT
let workers = {}
for (let i = 0; i < 20; i++) {
    console.log('Starting worker', i)
    let wf = workerFn.toString();
    wf = wf.substring(wf.indexOf('{') + 1, wf.lastIndexOf('}')) 
    const blob = new Blob([wf], { type: 'application/javascript' })
    const worker = new Worker(URL.createObjectURL(blob), { name: `worker${i}` })
    worker.onmessage = e => onWorkerMessage(`worker${i}`, e.data)
    workers[`worker${i}`] = worker
}

In order to run this code, it has to be served from a web server that sets the following response headers:

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

Sample HTML:

<!DOCTYPE html>
<html><script src="./atomics_bug.js"></script></html>

If you run this, you’ll see output on the console like this:
enter image description here

This behavior happens in both Firefox and Chrome.

I’ve gone though this minimal snippet for hours and it seems airtight to me, which leads me to believe that it is either a misunderstanding on my part or (less likely) a bug in JavaScript itself.

Another clue is that if I modify the code so the cooldown section has this:

        if (m.cooldown > 0) {
            // Since this should never change until the next postMessage, we should be able to wait on it
            let rv = Atomics.wait(sbuf.vi32, 0, 0, m.cooldown);
            if (rv !== 'timed-out') {
                // !!! This should never happen, yet it does
                throw new Error("How is this possible? Atomics.wait returned: " + rv);
            }
        }

Then I see lots of console errors that the Atomics.wait in the cooldown condition is not actually timing out, which again should be impossible since nothing should be able to modify sbuf.vi32[0] until the next postMessage has been sent.

How to prevent reloading page fs.writeFileSync()

I can’t prevent reloading page when i uncomment string fs.writeFile function. When i haven’t this function in my code, browser keeps it’s state and doesn’t reload the page.
How can i put my file in local directory and work with it without reloading?

I tried different ways of sending request to client and server, tried to write file in directory synchronously and nothing helps.
I have such code of my form in html:

<form id="metadata-form">
   <input type="file" id="file-input" required/>
   <button id="process-file-button" type="button">Check file</button>
</form>

There is my client code:

document.getElementById("process-file-button").addEventListener("click", async (event) => {
    event.preventDefault(); 

    const formData = new FormData();
    const fileInput = document.getElementById("file-input");
    
    if (!fileInput.files.length) {
        alert("Выберите файл для загрузки!");
        return;
    }

    formData.append("file", fileInput.files[0]);

    try {
        const response = await fetch("http://localhost:3000/process-file", {
            method: "POST",
            body: formData,
        });

        if (!response.ok) {
            throw new Error("Error sending to server");
        }

        const result = await response.json();
        console.log(result)
    } catch (error) {
        console.error("Error:", error);
    }
});

And part of server:

app.post("/process-file", async (req, res) => {
  if (!req.files || !req.files.file) {
    return res.status(400).json({ error: "Файл не загружен" });
  }
  

    const uploadedFile = req.files.file;
    const tempFilePath = path.join(__dirname, "uploads", uploadedFile.name);

   fs.writeFile(tempFilePath, uploadedFile.data, (err) => {
    if (err) {
        console.error("Ошибка при сохранении файла:", err);
        return res.status(500).json({ error: "Ошибка сохранения файла" });
    }
    console.log("Файл успешно сохранен:", tempFilePath);
    res.json("Success")
  });
});

How can i put my file in local directory and work with it without reloading?

ES import in JavaScript modules used from Jest

npx jest test/test.ts produces:

...
    XXX/src/declarations/package_manager/index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { Actor, HttpAgent } from "@dfinity/agent";
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module
...

Note that src/declarations/package_manager/index.js is a generated JS file that uses ES imports (and I cannot change that). This file is indirectly (through another module) imported from test/test.ts.

jest.config.js:

/** @type {import('ts-jest').JestConfigWithTsJest} **/
module.exports = {
  preset: 'ts-jest/presets/default-esm', // Use this preset to handle ES modules
  testEnvironment: "node",
  transform: {
    "^.+.tsx?$": ["ts-jest",{useESM: true}],
  },
  extensionsToTreatAsEsm: ['.ts'],
  // moduleNameMapper: {
  //   // If you're using non-ESM packages, you might need to map them correctly
  //   '^(\.{1,2}/.*)\.js$': '$1',
  // },
};

How to make my .ts tests to use .js files with import inside these .js without an error?

Why did example 1 give me 15 unique characters while example 2 gives me 15 of the SAME character? [duplicate]

I’m new to JavaScript (and coding in general), and I was hoping someone could help me understand why I got the results I did in two different examples.

I am creating a password generator. Once a button is clicked, two passwords with 15 different characters should appear. The code includes an array, Math.random, and a for loop.

In example 1, the code gave 15 unique characters (0M,OL#v4v9*C?.Z). In example 2, the code gave 15 of the same characters (MMMMMMMMMMMMMMM).

Example 1 gave me 15 different characters from the array (which is what I wanted):

const characters = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9","~","`","!","@","#","$","%","^","&","*","(",")","_","-","+","=","{","[","}","]",",","|",":",";","<",">",".","?",
"/"];

let passwordLength = 0
let password1El = document.getElementById("password1-el")
let password2El = document.getElementById("password2-el")
let passwordsBtn = document.getElementById("passwords-btn")

passwordsBtn.addEventListener("click", function() {
    passwordLength = 15
    for (let i = 0; i < passwordLength; i++) {
        password1El.textContent += characters[Math.floor(Math.random() * characters.length)];
        password2El.textContent += characters[Math.floor(Math.random() * characters.length)]
        }
})

Example 2 gave me 15 of the same characters from the array (which is not what I wanted):

const characters = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9","~","`","!","@","#","$","%","^","&","*","(",")","_","-","+","=","{","[","}","]",",","|",":",";","<",">",".","?",
"/"];

let passwordLength = 0
let password1El = document.getElementById("password1-el")
let password2El = document.getElementById("password2-el")
let passwordsBtn = document.getElementById("passwords-btn")

passwordsBtn.addEventListener("click", function() {
    passwordLength = 15
    let index1 = Math.floor(Math.random() * characters.length)
    let index2 = Math.floor(Math.random() * characters.length)
    for (let i = 0; i < passwordLength; i++) {
        password1El.textContent += characters[index1];
        password2El.textContent += characters[index2]
        }
})

I just want to make sure I understand the difference in what I was asking in each example. I appreciate anyone who can take the time to help me.

Thank you!

Order of operation in Java

I have trouble tracing and understanding how Java (and Javascript) is handling the following code:

// Java
int   i = 0;
int[] a = {10, 20, 30, 40, 50, 60};

a[++i] = a[i++] = a[++i] = ++i;
System.out.println(Arrays.toString(a));
// [10, 4, 30, 4, 50, 60]

let   i = 0;
const a = [10, 20, 30, 40, 50, 60];

a[++i] = a[i++] = a[++i] = ++i;
console.log( JSON.stringify(a));  // [10, 4, 30, 4, 50, 60]

When run, the output is [10, 4, 30, 4, 50, 60].

We can even simplify this example:

int   i = 0;
int[] a = {10, 20};

a[i] = ++i;
System.out.println(Arrays.toString(a));
// [1, 20]

let   i = 0;
const a = [10, 20];

a[i] = ++i;
console.log( JSON.stringify(a) );  // [1, 20]

I expected this to output [10, 1] because right-hand-side first. But the output is [1, 20], but how?

How to transfer accepted image from JavaScript to Python in Flask

I’m trying to create a website that tells what the given image is. I could not find a way to transfer the given image from JS to Python. I am using Flask.

JavaScript-

    // Photo Upload and Analysis
    document.getElementById('upload-photo').addEventListener('change', function (event) {
        const file = event.target.files[0];
        if (file) {
            const reader = new FileReader();
            reader.onload = function (e) {
                const resultDiv = document.getElementById('result');
                resultDiv.innerHTML = '<p>Analyzing...</p>';
                // Placeholder for analysis result (replace with real AI analysis code)
                setTimeout(function ()) {
                    const randomResult = Math.random() > 0.5;
                    if (randomResult) {
                        resultDiv.innerHTML = '<p>This object is recyclable! It can be recycled into new materials such as plastic bottles, paper products, or metal items.</p>';
                    } else {
                        resultDiv.innerHTML = '<p>This object is not recyclable. Please dispose of it properly to avoid harming the environment.</p>';
                    }
                }, 2000);
            };
            reader.readAsDataURL(file);
        }
    });

How to show the download progress bar? [duplicate]

I have a form that takes user data and allows them to add files. I want to add a progress bar, but in order to do this I need to stay on the same page. The data is written to a database once its been verified. I have included the form the progress bar and the data retrieval that I have attempted.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            #progress-container {
                width: 100%;
                background: #f3f3f3;
                border: 1px solid #ccc;
                border-radius: 5px;
                margin-top: 10px;
                display: none;
            }
            #progress-bar {
                height: 20px;
                width: 0;
                background: #4caf50;
                border-radius: 5px;
            }
        </style>
    </head>
    <body>
        <form method="POST" name="contact" enctype="multipart/form-data" id="upload-form">
            <fieldset>
                <p>
                    <input type="text" name="author" id="author">
                    <br />
                    <input type="date" id="date" name="date" 
                    min="2018-12-31"
                    max="<?php echo date('Y-m-d');?>" 
                    value="<?php echo date('Y-m-d');?>">
                    <br />
                    <input type="text" id="title" name="title" placeholder="Headline">
                    <br />
                    <textarea id="text" name="text" placeholder="Text of post" style="width:50%;height:10rem"></textarea>
                </p>
                <input type="file" id="files" name="files[]" multiple>
                <div class="row">
                    <div class="col-75">
                        <br />
                        <input type="submit" value="Post" name="submit"/>
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                        <input type="reset" value="Reset"/>
                        <br />
                    </div>
                </div>
            </fieldset>
        </form>
        
        <div id="progress-container">
            <div id="progress-bar"></div>
        </div>
    
        <script type="text/javascript">
            document.getElementById('upload-form').addEventListener('submit', function(event) {
                event.preventDefault(); // Prevent the form from submitting normally
    
                const formData = new FormData(this);
                const xhr = new XMLHttpRequest();
    
                // Show the progress bar
                const progressContainer = document.getElementById('progress-container');
                const progressBar = document.getElementById('progress-bar');
                progressContainer.style.display = 'block';
    
                // Track upload progress
                xhr.upload.addEventListener('progress', function(e) {
                    if (e.lengthComputable) {
                        const percentComplete = (e.loaded / e.total) * 100;
                        progressBar.style.width = percentComplete + '%';
                    }
                });
    
                // Handle the response from the server
                xhr.onload = function() 
                {
                    let note = '';
                    if (xhr.status === 200) 
                    {
                        note = 'Uploaded successful!';
                    } else {
// note = xhr.status;
                        note = 'Failed to uploaded';    
                    }
                    alert(note);
                    progressContainer.style.display = 'none'; // Hide the progress bar
                };
    
                // Open the request and send the form data
                xhr.open('POST', 'upload.php', true);
                xhr.send(formData);
            });
        </script>
        <?php
            if ($_SERVER['REQUEST_METHOD'] === 'POST') 
            {
                $author = trim(filter_var($_POST['author'], FILTER_SANITIZE_STRING));
                $date = date('Y/m/d', strtotime(preg_replace('([^0-9/])', '', $_POST['date'])));
                $title = trim(filter_var($_POST['title'], FILTER_SANITIZE_STRING));
                $text = trim(htmlspecialchars(filter_var($_POST['text'], FILTER_SANITIZE_STRING)));
            }
        ?>
    </body>
</html>

I had the set up as a separate php files and passed the data via POST. I have attempted to bring over the same code, but it is not clear as to how to actually make the call from the html form.