Tips on altering the appearance of a Lit Element when a specific action occurs

(I'm new to the Lit element environment, so please forgive my rookie question)

Code Overview

Below is the code for a File Uploader web component created using Lit Element. When a file is selected, the _inputHandler function validates the file. If it's valid, it enables/triggers the upload functionality to the server side.

Inquiry

How can I apply the CSS styling of visibility:visible to the #cancel-btn when a file is selected?

(By default/upon page load) The cancel button remains hidden until a file is chosen.

Once a valid file is selected, the Cancel button should become visible (e.g., set to visibility: visible).

The complete code for Uploader.ts :


import { html, LitElement, css } from "lit";
import { customElement, property, query } from "lit/decorators.js";

import { styles } from "./Style.Uploader.js";

@customElement("file-uploader")
export class Uploader extends LitElement {
  // CSS Styling
  static get styles() {
    return styles;
  }

  // Properties
  @property()
  fileName = `Accepted File Types : ${getValidFileTypes().toString()}`;

  @property() fileType = "";

  @property() fileSizeInKB: Number = 0;

  private files: FileList | null = null;

  // Actual HTML elements Rendered

  render() {
    return html`
      <section>
        <form action="" autocomplete="off" enctype="multipart/form-data">
          <h3>Upload your File</h3>
          <div class="box" id="box">
            <input
              type="file"
              name="uploadedFile"
              id="input-box"
              class="input-box"
              style="display: none"
              @change="${this._inputHandler}"
            />
            <label for="input-box" class="input-label" id="input-label">
              ${this.fileName}
            </label>
          </div>

          <div class="buttons">
            <button
              class="upload-btn"
              id="upload-btn"
              @click="${this._uploadHandler}"
            >
              <span class="upload-btn-span" id="upload-btn-span">
                &#8682; Upload
              </span>
              <span class="uploading-span" id="uploading-span">
                Uploading...
              </span>
            </button>

            <button
              class="cancel-btn"
              id="cancel-btn"
              @click="${this._cancelHandler}"
            >
              Cancel
            </button>
          </div>

        </form>
      </section>
    `;
  }

  @query("upload-btn") uploadButton!: HTMLButtonElement;

  get cancelButton() {
    return this.querySelector("#cancel-btn"); // ?? null
  }

  // @query("cancel-btn") cancelButton!: HTMLButtonElement;

  private async _inputHandler(e: Event) {
    const input = e.target as HTMLInputElement;

    // array of files selected to upload
    this.files = input.files;

    if (!(this.files && this.files[0])) {
      return;
    } else {
      const uploadedFileSize = this.files[0]?.size;
      const uploadedFileName = this.files[0]?.name;

      const uploadedFileType =
        FileExtensionService.getFileExtension(uploadedFileName);


      // Trying to Change the visibility of the Cancel button to visible
      this.cancelButton!.style.visibility = "visible";

      // Validating file size and file type
      const validFileSize = await validateFileSize(uploadedFileSize);
      const validFileType = await validateFileType(uploadedFileType);
      if (!validFileSize.isValid) {
          ...
      }
    }
  }

  /**
   *
   * @returns
   */
  private _cancelHandler(e: Event) {
    e.preventDefault();
    this.files = null;
    this.fileName = "";
    this.fileType = "";
    this.fileSizeInKB = 0;
    this.requestUpdate();
  }
}

I am attempting to modify the button's style (which I believe I can access through a getter or @query) but encountering an Error:

Property 'style' does not exist on type 'Element'.ts(2339)
for:
this.cancelButton!.**style**.visibility = "visible";

Answer №1

If you want to dynamically style the cancel button based on another property/state, you can utilize the built-in directive called styleMap().

For example

render() {
  return html`
    ...
            <button
              class="cancel-btn"
              id="cancel-btn"
              style=${styleMap({ visibility: this.files?.length ? 'visible' : 'hidden' })}
              @click="${this._cancelHandler}"
            >
    ...
  `;
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can I retrieve query parameters in the Server app directory of Next.js 13 using a function?

I am looking to retrieve a query token from localhost/get/point?token=hello. import { NextResponse } from 'next/server' import base64url from 'base64url' type Params = { token: string } export async function GET(req: Request, contex ...

An error occurred when trying to access object references within a function

Here is a snippet of my code: const fn1 = (param1: string, param2: string, param3: string): Promise<void> => {return new Promise()} const fn2 = (param1: string, param2: string): void => {return} const options = { option1: fn1, option2: ...

Generate a versatile Union type featuring a mapped property

I am currently working with different types of data enum DataTypes { Email = 'email', Checkbox = 'checkbox', } type DataTypeValues = { [DataTypes.Email]: string; [DataTypes.Checkbox]: boolean; }; type Type1<T extends DataTy ...

Accessing global variables after using the setInterval function can be tricky. Sometimes, despite setting the variable, it may still return undefined or

I have a typescript class where I am encountering some issues with accessing the starttime and count in the setInterval function. Even though I have set their values before, I am seeing undefined and NaN results. How can I resolve this problem? startTim ...

Encountered an issue with importing a TypeScript module

One issue I encountered is that when importing a module in an app.ts script, the '.js' extension is not included in the import line of the compiled js file. In my app.ts file, I have import {ModuleA} from './ModuleA' After compilation ...

Validator returns undefined when expressing invalid data

Having an issue with validation, here is the code snippet: routes.js var express = require('express'); var router = express.Router(); var hello_controller = require('../api/controllers/helloController'); var { validationRules, validat ...

Can an object be required to be spread strictly?

Is there a way to enforce strict spreading of objects in TypeScript? Consider the example below: interface Foo { a: string; } interface Bar { a: string; b: number; } const barObject: Bar = { a: "a string", b: 1 }; // Should generate a warning du ...

Learn how to retrieve the return data from two combined objects using Angular's TypeScript syntax

I've encountered an issue with TypeScript syntax, specifically when a WebAPI returns a DTO containing two objects. The object being returned looks like this: { "userList": [{ "id": 1, "firstNm": "John", "lastNm": "Doe" }, ...

"Encountering a glitch in the Typescript/Node API where Express routes

Encountering a peculiar issue here - when attempting to import my router from an external file and add it as a route, I keep getting this unusual error where the string appears to be enclosed in double quotes. https://i.sstatic.net/nm9Wn.png ...

Utilizing ExpressJS in a NodeJS application with ES6 and Typescript

After confirming my information, I discovered that in an ES6 application, it is necessary to import dependencies using import .. from '..' instead of var .. = require('..'). I made the necessary changes to the imports, but encountered ...

Resize event of an Angular2 application within an iframe has been triggered

My current project involves embedding an Angular2 application within a Liferay portlet using iframes. The Liferay tomcat server is hosted on a different domain than the Angular2 application, and I am facing challenges with dynamically resizing the iframe b ...

Is it possible to silence the other person's audio using livekit?

As a developer, I create meeting apps using React and livekit technology. I am looking for a reliable method to silence the audio of other participants in the virtual room. Any suggestions? ...

Step-by-step guide on navigating back in Angular 12 without triggering a page refresh

As an illustration, consider a scenario where I input values into a table and move to the next page. Upon returning to the page, I expect the entered values to still be present. I attempted to achieve this using this._location.back(), but instead of disp ...

retrieve a function from a Firestore service

Is there a way to utilize a function from a service within a component? I am attempting to use the following code: addProyecto(proyecto: Proyecto) { this.proyectosCollection.add(this.proyecto); } However, I am encountering this error message: TypeEr ...

How to send Multipart form data with a string payload

Many suggestions in regards to this issue recommend utilizing some form of FormData within nodejs for building a multipart form. However, I am seeking to achieve the same result without relying on the FormData library. Instead, I aim to use only request h ...

Loading screen displayed while transitioning between routes within Angular

I have been struggling to implement a loading spinner in my project. How can I display a loading screen when changing routes in Angular? Here is the HTML code snippet: <div *ngIf="showLoadingIndicator" class="spinner"></div> ...

How can you type a collection of initialized class instances in Typescript when given an object containing classes?

Imagine having an object that resembles the following: const typeMap = {category1: Category1, category2: Category2} In this case, Category1 and Category2 refer to classes, and there could potentially be hundreds of different categories. Now I also have a ...

Restrict function signatures in Typescript to only accept class or object methods

In my quest to create a function signature in Typescript, I am looking to develop a calling function that takes an object, its method name, and arguments to be applied. Here is an example of it in action: const obj = { do(...args) { console.log(arg ...

Create a pinia state by defining it through an interface without the need to manually list out each property

Exploring the implementation of state management (pinia) within a single-page application is my current task. We are utilizing typescript, and I am inquiring about whether there exists a method to define a state based on an interface without needing to ret ...

Troubleshooting an Ionic 3 application on a Mac with an iOS emulator

Currently, I am attempting to troubleshoot Ionic 3 TypeScript files using Safari developer tools. I have successfully enabled emulation and am able to detect the emulator on Safari. Within my project, I have various pages and components files, but I am st ...