cuencadelrio
cuencadelrio

Reputation: 145

How to use href with typescript?

I am developing a pdf download form from a drupal api, the pdfs are mapped within the options of a select, when I select a pdf when I hit the download button it has to open the link where the pdf is located and from there it can be downloaded. I picked up the value of the selected option and put a tag to redirect the page to the address where the pdf is, but it does not let me use the href, it gives me the following error: The expected type comes from property 'href' which is declared here on type 'DetailedHTMLProps<AnchorHTMLAttributes, HTMLAnchorElement>', how can I fix this error. Or maybe there is another way to do it without the href?

import React from 'react'
import { forwardRef, AnchorHTMLAttributes, HTMLAttributes} from 'react'
import { useState, useEffect, useRef } from 'react'
import { getDocument } from '../../api/drupalAPI'
import { Document } from '@icofcv/common';

type AnchorProps = AnchorHTMLAttributes<HTMLAnchorElement>


export function Manuals () {

    const [documents, setDocuments] = useState<Document[]>([]);
    const [inputValue, setInputValue] = useState("")
    const ref = useRef<HTMLAnchorElement>(null)
    const [isLoading, setIsLoading] = useState (false)

    const fetchDocuments = async () => {
        setIsLoading(true)
        getDocument().then((response) => {
            console.log(response)
            setDocuments(response);
            setIsLoading(false)
        }).catch((error) => {
            console.error(error);
            throw error;
        });
    }

    useEffect(() => {
        
        fetchDocuments();
    }, []);

    return(
        <>
        <div className="card bg-white px-2 py-3 md:p-6">
            <h1 className="pb-3 font-medium">Manuales de Estándares</h1>
            <div className="card-body py-2 md:px-12 mx-auto w-100">
                <p className="text-neutral-600 text-sm mb-2">Manual de estándares de la práctica de la Fisioterapia en Centros Sanitarios</p>
                <button className="btn bg-teal-600 hover:bg-teal-700 text-white px-8 w-40" type="button">Descargar</button>
                <p className="text-neutral-600 text-sm font-bold my-2">Desde el siguiente formulario podrá descargar los anexos del manual, se han clasificado en 2 grupos para una mejor búsqueda.</p>
               
                <div className="flex flex-col md:flex-row items-end justify-between my-4">
                    <div className="relative z-0 w-full group">
                   
                        <label className="block text-sm font-medium text-gray-900 mb-2">Anexos Estándares*</label>
                       
                        <select  onChange={(e) => setInputValue(e.target.value)} id="" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5">
                        <option  selected>Seleccione Anexo I</option>
                        {documents.map(docu => (
                        <>
                            
                            <option  key={docu.id} selected>{docu.contentUrl}</option>
                           
                           
                             </>
                             
                         ))}
                          
                        </select>
                    </div> 
                    <a ref={ref} href={(e: React.FormEvent<HTMLInputElement>) => { const newValue = e.currentTarget.value;setInputValue(newValue)}}></a>
                   
                </div>
                <div className="flex flex-col md:flex-row items-end justify-between my-4">
                    <div className="relative z-0 w-full group">
                        <label className="block text-sm font-medium text-gray-900 mb-2">Anexos Estándares*</label>
                        <select id="" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5">
                            <option selected>Seleccione Anexo II</option>
                        </select>
                    </div>
                    <button className="btn bg-teal-600 hover:bg-teal-700 text-white px-8 ml-4 w-full md:w-40 my-2 md:my-0" type="button">Descargar</button>
                </div>
                <div className="flex flex-col md:flex-row items-end justify-between my-4">
                    <div className="relative z-0 w-full group">
                        <label className="block text-sm font-medium text-gray-900 mb-2">Anexos Estándares*</label>
                        <select id="" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5">
                            <option selected>Seleccione Anexo III</option>
                        </select>
                    </div>
                    <button className="btn bg-teal-600 hover:bg-teal-700 text-white px-8 ml-4 w-full md:w-40 my-2 md:my-0" type="button">Descargar</button>
                </div>
            </div>
        </div>
        </>
    )
}

Upvotes: 2

Views: 8131

Answers (1)

Linda Paiste
Linda Paiste

Reputation: 42160

An <a> element is a link and the href is the string of the URL that you are linking to. An href cannot be a function. If you need a function, you can use a different prop such as onClick.

when I select a pdf when I hit the download button it has to open the link where the pdf is located and from there it can be downloaded. I picked up the value of the selected option and put a tag to redirect the page to the address where the pdf is

It looks like you are trying to have a "Descargar" ("Download") button that will the open the currently selected PDF URL in a new window.

You don't need refs for this because you already have the selected document URL in your inputValue state.

Using onClick

One way to set this up is to use an onClick handler of the <button> which can execute any code that you want. You can call window.open() and use "_blank" to open in a new window. We can disable the button if no document has been selected.

<div>
  <div>
    <label htmlFor="anexo-i">
      Anexos Estándares*
    </label>

    <select
      onChange={(e) => setInputValue(e.target.value)}
      value={inputValue}
      name="anexo-i"
      id="anexo-i"
    >
      <option value="">Seleccione Anexo I</option>
      {documents.map((docu) => (
          <option key={docu.id} value={docu.contentUrl}>
            {docu.name}
          </option>
      ))}
    </select>
  </div>

  <button
    type="button"
    disabled={!inputValue}
    onClick={() => window.open(inputValue, '_blank')}
  >
    Descargar
  </button>
</div>

Using href

You can use an <a> element to handle the downloading. You could open the PDF in a new window with target="_blank" but you can also make use of the download attribute of the <a> element.

An <a> element can also have an onClick handler to execute any code. You can call e.preventDefault() in your custom code to prevent navigating to the URL and use your own handling instead. Here I am using the onClick to handle the "disabled" behavior. You'll probably want to change the styling when it is disabled as well, since the <a> does not have the same built-in disabled behavior as the <button>.

<div>
  <div>
    <label htmlFor="anexo-i">
      Anexos Estándares*
    </label>

    <select
      onChange={(e) => setInputValue(e.target.value)}
      value={inputValue}
      name="anexo-i"
      id="anexo-i"
    >
      <option value="">Seleccione Anexo I</option>
      {documents.map((docu) => (
        <option key={docu.id} value={docu.contentUrl}>
          {docu.name}
        </option>
      ))}
    </select>
  </div>

  <a
    className={
      inputValue ? "your regular styles" : "your disabled styles"
    }
    role="button"
    href={inputValue}
    target="_blank"
    onClick={(e) => {
      if (!inputValue) {
        e.preventDefault();
        alert("Please select a file");
      }
      // otherwise, do the default behavior
    }}
  >
    Descargar
  </a>
</div>

CodeSandbox with both approches.

Upvotes: 3

Related Questions