EFB App dev - various issues

EDIT: I solved it. See post nr 3.

Hello together.

Im not very experienced with node but nowadays chatgpt can be help with these things. But we cant get further, so i hope someone can help me, ive spent over 4h now on this issue alone.

Im trying to set an image to a div. A very simple task. But i cant find out how to do it here.

I have a toolbar and flow pro javascript app that i want to convert to the efb node.js way. In this app i have, besides other functions, one where the user can insert an ICAO into a textfield.
Pressing enter it searches a json file on our server. In this json file hundreds of entries are, in a form like this:

 {
        "icao": "CYUL",
        "city": "Montreal",
        "airportName": "Montreal \/ Pierre Elliott Trudeau International Airport",
        "path": "assets\/img\/icaos\/cyul.png"
    },

If the icao entry is found in this file, the img path (“path” in json) is filled into the src attribute in a html div. This is what im trying to do now. But i cant get the image into the src attibute, no matter what way.
We have tried over 15 different ways now. This is the last version.

import { GamepadUiView, RequiredProps, TextBox, TTButton, TVNode, UiViewProps } from "@efb/efb-api";
import { FSComponent, Subject } from "@microsoft/msfs-sdk";
import "./ICAOSearch.scss";

interface ICAOPageProps extends RequiredProps<UiViewProps, "appViewService"> {
  title: string;
  color: string;
}

export class ICAOSearch extends GamepadUiView<HTMLDivElement, ICAOPageProps> {
  public readonly tabName = ICAOSearch.name;

  private readonly icaoModel = Subject.create<string>("");
  private readonly searchResultModel = Subject.create<string>("");

  constructor(props: ICAOPageProps) {
    super(props);
  }

  private handleInput = (element: HTMLInputElement): void => {
    console.log("handleInput triggered");
    const value = element.value.trim().toUpperCase();
    this.icaoModel.set(value);
  };

  private getAirportInfo = (): void => {
    let search_text = this.icaoModel.get().toLowerCase().replace(/\d/g, "").trim();
    if (search_text.length > 4) search_text = search_text.slice(0, 4);

    console.log("Search triggered with search_text:", search_text);

    const xhr = new XMLHttpRequest();
    const filePath = "https://blackbox711.com/icaos.json";

    console.log("Opening XMLHttpRequest to:", filePath);
    xhr.open("GET", filePath, true);
    xhr.responseType = "json";

    xhr.onload = () => {
      console.log("XHR onload triggered, status:", xhr.status);
      if (xhr.status === 200) {
        const icaos = xhr.response;
        console.log("JSON data loaded:", icaos);

        const foundEntry = icaos.find(
          (entry: { icao: string }) => entry.icao.toLowerCase() === search_text
        );
        console.log("Found entry:", foundEntry);

        if (foundEntry) {
          const fullImgUrl = "https://blackbox711.com/" + foundEntry.path;
          console.log("Setting image URL to:", fullImgUrl);
          this.searchResultModel.set(fullImgUrl);
        } else {
          console.log("No matching ICAO found.");
          this.searchResultModel.set(""); // Empty string or fallback URL
        }
      } else {
        console.log("Error loading ICAO data.");
        this.searchResultModel.set(""); // Empty string or fallback URL
      }
    };

    xhr.onerror = () => {
      console.log("Network error occurred.");
      this.searchResultModel.set(""); // Empty string or fallback URL
    };

    console.log("XHR request sent.");
    xhr.send();
  };

  public render(): TVNode<HTMLDivElement> {
    const imageSrc = this.searchResultModel.get() || "https://www.blackbox711.com/assets/img/icaos/edds.png"; // Use fallback if model is empty

    return (
      <div
        ref={this.gamepadUiViewRef}
        class="bb711-icao-page"
        style={`--color: ${this.props.color}`}
      >
        <div class="header">
          <TTButton
            key="Go back"
            type="secondary"
            callback={(): void => {
              this.props.appViewService.goBack();
            }}
          />
          <h2>{this.props.title}</h2>
        </div>

        <div class="content">
          <p>Enter an ICAO to search for available extra airport information.</p>

          <TextBox
            placeholder="Enter your Airport ICAO"
            model={this.icaoModel}
            onInput={this.handleInput}
            showDeleteIcon={true}
            focusOnClear={true}
            debounceDuration={300}
          />

          <TTButton key="Search ICAO" callback={this.getAirportInfo} />

          <div class="search-result">
            <p>
              <img
                src={imageSrc}
                style="max-width: 100%; height: auto;"
              />
            </p>
          </div>
        </div>
      </div>
    );
  }
}

Its not a CORS issue or something, i have set server headers. Debugger is not giving errors.

Can you please let me know how one would do that here? So what is the way to write into an image src attribute.
Atm if one is starting this app all the console.logs you see in the code show correct data. So i read the json file correct, the image path is correct, i only cannot get it into the src attribute. I can write it into a p tag no issue.

Thanks for help with this.

Besides that there are 2 other issues:

  1. sometimes i have to build the project multiple times to actually reflect the latest changes. The node watcher works and shows changes (without errors). But the build in editor builds but doesnt reflect the modification. 1-2 rebuilds needed sometimes, what makes it extremely difficult to find errors.
  2. the camera + keyboard bugs out and i cant use them anymore, requiring a restart. Also really time consuming. With restart i mean i ave to task kill msfs… beycause i doesnt recognize inputs anymore.

But i can live with it, the important part is the src attribute issue.

1 Like

Here the log with EDDF example:

image

Ok ive solved it in a different way. Instead of maipulating the img src i append the img to the dom.