Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Atributos en nuestro componente

20/22
Recursos

Aportes 10

Preguntas 4

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Si observaron la consola, lo más probable es que les haya salido este error

Uncaught RangeError: Maximum call stack size exceeded.
    at HTMLElement.attributeChangedCallback (product-card.js:16)
    at HTMLElement.attributeChangedCallback (product-card.js:16)
    at HTMLElement.attributeChangedCallback (product-card.js:16)
    at HTMLElement.attributeChangedCallback (product-card.js:16)
    at HTMLElement.attributeChangedCallback (product-card.js:16)
    at HTMLElement.attributeChangedCallback (product-card.js:16)
    at HTMLElement.attributeChangedCallback (product-card.js:16)
    at HTMLElement.attributeChangedCallback (product-card.js:16)
    at HTMLElement.attributeChangedCallback (product-card.js:16)
    at HTMLElement.attributeChangedCallback (product-card.js:16)

Esto se debe a que estamos utilizando el atributo “title” y este ya es un atributo nativo de HTML por lo que la solución es simplemente cambiar el nombre de nuestro atributo.

Hola les dejo el link del proyecto un poco personalizado y los aportes de varios de ustedes en el redme Nike

Espero les sirva 😃

No hay link para los retos 🙋🏽‍♂️

Para ahorrarse hacer muchos if pueden hacer esto:

    static get observedAttribute() {
        return ['img', 'name', 'price', 'description', 'colllection'];
    }
    attributeChangeCallback(attr, oldValue, newVal) {
        const attributes = productCard.observedAttribute;
        if (attributes.includes(attr)) {
            this[attr] = newVal;
        }
    }

Si queremos agregar otro atributo al componente solo sería agregarlo al observedAttribute y no tener que añadir otra condición.

Les comparto el código del componente al inicio de la clase:

class productCard extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: "open" });
  }
  getTemplate(){
    const template = document.createElement("template");
    template.innerHTML = `
    <main class="container">
      <section class="imgBox">
        <img src="./imgs/nike-blue.png" alt="Zapatos deportivos para correr color azul"/>
      </section>
      <section class="details">
        <div class="content">
          <h2>Hola mundo</h2>
          <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Assumenda quod deserunt itaque alias delectus earum, quis repellat veritatis ad temporibus ex recusandae quasi rem! Cumque sequi rem nam vero saepe!</p>
          <h3>$300 USD</h3>
          <button>Comprar</button>
        </div>
      </section>
    </main>
    ${this.getStyles()}
    `;
    return template;
  }
  getStyles() {
    return `
      <style>
      :host {
        --primary-background: #5a6cb2;
          width: 80%;
          max-width: 900px;
          min-width: 280px;
          margin: 0 auto;
      }
      .container {
          position: relative;
          display: flex;
          flex-wrap: wrap;
          justify-content: space-between;
          width: 900px;
          height: 600px;
          margin: 20px;
          background-color: #fff;
      }
      .container .imgBox {
          position: relative;
          display: flex;
          justify-content: center;
          width: 50%;
          height: 100%;
          background-color: var(--primary-background)
      }
      .container .imgBox:before {
          position: absolute;
          top: 20px;
          left: 20px;
          font-size: 8em;
          font-weight: 800;
          color: #000;
          content: 'Nike';
          opacity: 0.1;
      }
      .container .imgBox img {
          position: relative;
          top: 100px;
          left: -50px;
          width: 720px;
          height: 480px;
          transform: rotate(-30deg);
      }
      .container .details {
          display: flex;
          justify-content: center;
          align-items: center;
          width: 50%;
          height: 100%;
          box-sizing: border-box;
          padding: 40px;

      }
      .container .details h2 {
          margin-bottom: 25px;
          font-size: 2.5em;
          line-height: 0.8em;
          color: #444;
      }
      .container .details h2 span {
          font-size: 0.4em;
          text-transform: uppercase;
          letter-spacing: 2px;
          color: #999;
      }
      .container .details p {
          max-width: 85%;
          margin-left: 15%;
          margin-bottom: 35px;
          color: #333;
          font-size: 15px;
      }
      .container .details h3 {
          float: left;
          font-size: 2.5em;
          color: #a2a2a2;
      }
      .container .details button {
          margin-top: 35px;
          float: right;
          padding: 15px 20px;
          font-size: 16px;
          color: #fff;
          letter-spacing: 1px;
          font-weight: 600;
          text-transform: uppercase;
          border-radius: 40px;
          background-color: #5a6cb2;
          cursor: pointer;
      }
      @media (max-width: 1080px) {
          .container {
              height: auto;
              width: auto;
          }
          .container .imgBox {
              padding: 40px;
              width: 100%;
              box-sizing: border-box;
              height: auto;
              text-align: center;
          }
          .container .imgBox img {
              left: initial;
              width: 100%;
              height: auto;
              transform: rotate(0deg);
          }

          .container .details {
              width: 100%;
              height: auto;
              padding: 20px;
          }

          .container .details p {
              max-width: 100%;
              margin-left: 0;
          }
      }
      </style>
    `;
  }
  render(){
    this.shadowRoot.appendChild(this.getTemplate().content.cloneNode(true));
  }
  connectedCallback(){
    this.render();
  }
}

customElements.define("product-card", productCard);

Hey!, al momento de utilizar atributos nativos de html para nuestro componente se suele generar este error en la consola como lo muestran algunos compañeros en otros comentarios

Uncaught RangeError: Maximum call stack size exceeded.

si bien se puede cambiar simplemente el atributo por otro En este enlace pueden encontrar algunas explicaciones de porque se genera ese problema y como solucionarlo 😉

Deje el link de la rama equivocada este es el bueno Nike

Les dejo mi v:

class CardComponent extends HTMLElement {

    constructor() {
        super();
        this.attachShadow({ mode: "open" });
    }

    connectedCallback() {
        this.render();
    }

    attributeChangedCallback(attr, oldValue, newValue) {
        if (newValue !== oldValue) {
            this[attr] = newValue;
        }
    }

    render() {
        this.shadowRoot.append(this.templates.content.cloneNode(true));
    }

    get templates() {
        const container = document.createElement('template');
        container.innerHTML = `
            <div class="card-container">
                <section class="card-container__img-content">
                    <h2>${this.mark}</h2>
                    <img src="${this.img}" alt="image product ${this.mark}">
                </section>
                <section class="card-container__main-content">
                    <h3>${this.product} <span>${this.category}</span></h3>
                    <h4>${this.title}</h4>
                    <p>${this.text}</p>
                </section>
                <section class="card-container__footer-content">
                    <h3>${this.price}</h3>
                    <button type="button">${this.button}</button>
                </section>
            </div>
            
            ${this.styles}
        `;
        return container;
    }

    get styles() {
        return `
            <style> 
            
            :host {
                --background-color-main-content: #758cf1;;
                --text-color-img-content: #00000054;
                --title-color-main-content: grey;
                --button-color-footer-content: white;
                --font-family: sans-serif, "Roboto Light";
                width: 100%;
                height: 100%;
                font-family: var(--font-family);
            }
            :host .card-container {
                width: 100%;
                height: 100%;
                display: grid;
                position: relative;
                grid-template-columns: 1fr;
                grid-template-rows: 250px auto 100px;
            }
            :host .card-container__img-content {
                width: 100%;
                height: 250px;
                background-color: var(--background-color-main-content);
            }
            :host .card-container__img-content h2 {
                color: var(--text-color-img-content);
                font-size: 100px;
                margin: 0;
                padding: 15px;
            }
            :host .card-container__img-content img {
                width: 100%;
                height: 250px;
                position: absolute;
                transform: translateY(-85px);
            }     
            :host .card-container__main-content {
                width: 100%;
            }
            :host .card-container__main-content h3 {
                font-size: 25px;
                font-weight: bold;
                margin: 30px 20px 10px 20px;
            }
            :host .card-container__main-content span {
                font-size: 15px;
                text-transform: uppercase;
                color: var(--title-color-main-content);
            }
            :host .card-container__main-content h4 {
                text-transform: uppercase;
                color: var(--title-color-main-content);
                margin: 0 10px 10px 20px;
                font-size: 15px;
            }
            :host .card-container__main-content p {
                padding: 0 20px 0 20px;
                margin-bottom: 0;
                font-size: 18px;
                line-height: 1.4;
                font-weight: 100;
            }
            :host .card-container__footer-content {
                    width: 100%;
                    height: 80px;
                    display: flex;
                    align-content: center;
                    justify-content: space-between;
                    align-items: center;
            }
            :host .card-container__footer-content h3 {
                color: var(--title-color-main-content);
                font-size: 30px;
                margin: 20px;
            }
            :host .card-container__footer-content button {
                margin-right: 20px;
                display: flex;
                color: var(--button-color-footer-content);
                background-color: var(--background-color-main-content);
                border-radius: 15px;
                width: 100px;
                height: 40px;
                align-items: center;
                justify-content: center;
                align-self: center;
                border: 1px solid transparent;
                font-weight: bold;
                font-size: 15px;
            }
            @media (min-width: 800px) {
                :host .card-container {
                    height: auto;
                    grid-template-columns: 1fr 1fr;
                    grid-template-rows: 1fr 1fr;
                }
                :host .card-container__img-content {
                    height: auto;
                    grid-column: 1 / 2;
                    grid-row: 1 / 3;
                }
                :host .card-container__img-content img {
                    width: 700px;
                    height: 400px;
                    transform: translate(-145px, -50px) rotate(330deg);
                }
                :host .card-container__main-content {
                    grid-column: 2 / 3;
                    grid-row: 1 / 2;
                }
                :host .card-container__main-content h3 {
                    margin: 30px 20px 10px 10px;
                }
                :host .card-container__footer-content {
                    height: 200px;
                    grid-column: 2 / 3;
                    grid-row: 2 / 3;
                }
                :host .card-container__footer-content h3 {
                    font-size: 40px;
                }
                :host .card-container__footer-content button {
                    width: 130px;
                    height: 50px;
                    font-size: 20px;
                    margin-right: 40px;
                }
               
            } 
            </style>
        `;
    }

    static get observedAttributes() {
        return ['mark', 'img', 'product', 'category', 'title', 'text', 'button', 'price'];
    }


}

customElements.define('card-component', CardComponent);

Que genial 😃

Como en nuestro componente de proyecto solo estamos recibiendo las propiedades desde el html, lo hice de una manera mas simple, pero igualmente valida, simplemente obteniendo los atributos de la data que necesito en el constructor, y funciona bien para el resultado que esperamos.