rusttauri

Emitting global event from Rust in Tauri


I'm new to Rust and Tauri and just created an app using cargo create-tauri-app and wanted to add a thread in Rust emitting a global event that is used to change a text in the frontend. However, I cannot make it work. This is my code:

index.html (just adding a p-Element #test-msg)

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="styles.css" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Tauri App</title>
    <script type="module" src="/main.js" defer></script>
  </head>

  <body>
    <main class="container">
      <h1>Welcome to Tauri</h1>

      <div class="row">
        <a href="https://tauri.app" target="_blank">
          <img src="/assets/tauri.svg" class="logo tauri" alt="Tauri logo" />
        </a>
        <a
          href="https://developer.mozilla.org/en-US/docs/Web/JavaScript"
          target="_blank"
        >
          <img
            src="/assets/javascript.svg"
            class="logo vanilla"
            alt="JavaScript logo"
          />
        </a>
      </div>
      <p>Click on the Tauri logo to learn more about the framework</p>

      <form class="row" id="greet-form">
        <input id="greet-input" placeholder="Enter a name..." />
        <button type="submit">Greet</button>
      </form>
      <p id="greet-msg">Hallo1</p>
      <p id="test-msg">Hallo2</p>
    </main>
  </body>
</html>

main.js (adding testMsgEl, listen to events)

const { invoke } = window.__TAURI__.core;
const { listen } = window.__TAURI__.event.listen;

let greetInputEl;
let greetMsgEl;
let testMsgEl;

async function greet() {
  // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
  greetMsgEl.textContent = await invoke("greet", { name: greetInputEl.value });
}

listen<String> ('emit_from_rust', (event) => {
  testMsgEl.textContent = event.payload;
});

window.addEventListener("DOMContentLoaded", () => {
  greetInputEl = document.querySelector("#greet-input");
  greetMsgEl = document.querySelector("#greet-msg");
  testMsgEl = document.querySelector("#test-msg");
  document.querySelector("#greet-form").addEventListener("submit", (e) => {
    e.preventDefault();
    greet();
  });
});

lib.rs (I added the function test_emit and started it using .setup)

use std::{thread::sleep, time::Duration};
use tauri::{AppHandle, Emitter};

// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}! You've been greeted from Rust!", name)
}

fn test_emit(handle: AppHandle) {
    std::thread::spawn(move || {
        for i in 1..4 {
            sleep(Duration::from_secs(1));
            handle.emit("emit_from_rust", &format!("{i}!")).unwrap();
        }
    });
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_shell::init())
        .invoke_handler(tauri::generate_handler![greet])
        .setup(|app| {
            let handle = app.handle().clone();
            test_emit(handle);
            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

Solution

  • I found the problem:

    const { listen } = window.__TAURI__.event.listen;
    

    and then using listen does not work. Instead, using

    window.__TAURI__.event.listen('emit_from_rust', (event) => {
      testMsgEl.innerHTML = event.payload;
    });
    

    directly in the code just does what I wanted it to do.