Pasar al contenido principal
Penyaskito Blog

Main navigation

  • Home
Language switcher
  • English
  • Español
User account menu
  • Iniciar sesión

Sobrescribir enlaces de ayuda a la navegación

  1. Inicio

Drupal JavaScript behavior para destacar líneas de pedido editadas en el carrito de Drupal Commerce

Por penyaskito, 23 Mayo, 2021

Hay muchas formas de aprender algo, y a cada persona le funcionan mejor distintas opciones: algunos prefieren leer guías o artículos, otros prefieren videos, y otros prefieren ejemplos. A mi me funciona mejor con ejemplos, así que cuando necesito aprender algo nuevo en Drupal, intento recurrir al propio código de Drupal core.

Si necesitas conseguir algo con código y no tienes claro por dónde empezar, piensa: ¿dónde he visto esto yo antes?

Puede que encuentres un ejemplo en tu propio código. Este artículo cubre un caso de uso real que he tenido con Drupal Commerce, simplificado un poco por la brevedad del artículo. La historia de usuario sería algo como: Como cliente, quiero refrescar el carrito en lugar de continuar con la compra después de editar la cantidad de cualquier línea de pedido, para poder ver si hay descuentos mejores que apliquen por cuestiones de volumen de compras.  

Para nuestro formulario, esto significa: cuando esté en la página de Carrito, deshabilita el botón de Checkout cuando el usuario edite la cantidad, y habilita el botón de Actualizar carrito.

Screenshot of the Shopping cart before editing it
El formulario del carrito de Drupal commerce después de aplicar estilos horribles con el propósito de mostrar mejor las diferencias entre botones habilitados y deshabilitados.

Pero para una mejor experiencia de usuario, queremos marcar para el usuario qué líneas de pedido ha editado. ¿Dónde hemos visto esto antes? En el formulario de traducción de la interfaz.

Si habilitas el módulo locale, y añades algún otro idioma en tu web, tendrás la página de traducción de interfaz

The locale translation interface already mark edited translations, and that's in Drupal core
La UI de traducción de interfaz ya marca como editadas las traducciones que editamos, y es un ejemplo perfecto en el core de Drupal.

Así que vamos a mirar el código e inspeccionar cómo hacerlo. Para mí, la mejor forma si no estás familiarizado con ese código es buscar las cadenas de la interfaz afectadas, o la ruta de esa página en mi IDE, e indagar hasta que encuentro cómo funciona.

En este caso, si buscas "Changes made in this table" encuentras core/modules/locale/locale.admin.js. Los archivos JavaScript se incluyen vía libraries, por lo que buscando ese nombre de archivo te chocarás con la biblioteca drupal.locale.admin definida en core/modules/locale/locale.libraries.yml. 

Si buscas ahora esa biblioteca, terminas en varios formularios que la incluyen con:

$form['#attached']['library'][] = 'locale/drupal.locale.admin';

Pues esto es todo lo que está involucrado en hacer esta interfaz de traducciones, ahora sólo tienes que imitarlo.

Vamos a crear un módulo. El modo más rápido es con drush, ejecutando

ddev drush generate module-standard

He seleccionado commerce_cart_forcerefresh como nombre. Para el resto de opciones, he seleccionado generar el archivo libraries, que quedará así:

commerce_cart_forcerefresh:
  js:
    js/commerce-cart-forcerefresh.js: {}
  css:
    component:
      css/commerce-cart-forcerefresh.css: {}
  dependencies:
    - core/jquery
    - core/drupal
    - core/drupal.form
    - core/jquery.once

 En nuestro css:

form#views-form-commerce-cart-form-default-1 tr.changed {
  background: #ffb;
}

Y en nuestro JavaScript:

(function ($, Drupal, drupalSettings) {
  'use strict';

  Drupal.behaviors.cartForceRefresh = {
    attach: function (context) {
      var $form = $('form#views-form-commerce-cart-form-default-1').once('cartItemDirty');
      var $updateSubmit = $('form#views-form-commerce-cart-form-default-1 #edit-submit')
        .prop('disabled', true);

      if ($form.length) {
        $form.one('formUpdated.cartItemDirty', 'table', function () {
          var $marker = $(Drupal.theme('cartItemChangedWarning')).hide();
          $(this).addClass('changed').before($marker);
          $marker.fadeIn('slow');
        });

        $form.on('formUpdated.cartItemDirty', 'tr', function () {
          var $row = $(this);
          var marker = Drupal.theme('cartItemChangedMarker');

          $row.addClass('changed');

          var $updateSubmit = $('form#views-form-commerce-cart-form-default-1 #edit-submit')
            .prop('disabled', false);
          var $checkoutSubmit = $('form#views-form-commerce-cart-form-default-1 #edit-checkout')
            .prop('disabled', true);

          if ($row.length) {
            $row.find('td:first-child .js-form-item').append(marker);
          }
        });
      }
    },
    detach: function (context, settings, trigger) {
      if (trigger === 'unload') {
        var $form = $('form#views-form-commerce-cart-form-default-1').removeOnce('cartItemDirty');
        if ($form.length) {
          $form.off('formUpdated.cartItemDirty');
        }
      }
    }
  };
  $.extend(Drupal.theme, {
    cartItemChangedMarker: function cartItemChangedMarker() {
      return '<abbr class="warning ajax-changed" title="' + Drupal.t('Changed') + '">*</abbr>';
    },
    cartItemChangedWarning: function cartItemChangedWarning() {
      return '<div class="clearfix messages messages--warning">' + 
        Drupal.theme('cartItemChangedMarker') + ' ' + 
        Drupal.t('Update the cart for the changes to take effect.') + '</div>';
    }
  });
})(jQuery, Drupal, drupalSettings);

Ojo que el id del formulario se usa en varias partes de nuestro css y javascript, y que depende del id de la view de Drupal. Tenlo en cuenta si no usas la vista por defecto, si tienes diferentes tipos de pedido, etc. En mi caso real, mi tema ya proveía una clase css en ese formulario que podía usar en lugar del id.  

Lo último es asegurar que el behavior se añade a nuestro formulario. La forma más sencilla para esta demo es implementar hook_form_FORMID_alter(), que también depende del id de la vista. Nuestro archivo commerce_cart_forcerefresh.module es:

<?php

use Drupal\Core\Form\FormStateInterface;

/**
 * @file
 * Primary module hooks for commerce_cart_forcerefresh module.
 */
function commerce_cart_forcerefresh_form_views_form_commerce_cart_form_default_1_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['#attached']['library'][] = 'commerce_cart_forcerefresh/commerce_cart_forcerefresh';
}

Y produce el resultado esperado:

Final result with order line items cues when they were edited.
El botón de Checkout se deshabilita, el botón de Actualizar carrito se habilita, se añade un indicador a cada línea de pedido editada, y se muestra un aviso en la parte superior de la página.

¡Espero que sirva! Todo el código lo tienes en https://github.com/penyaskito/drupal_commerce_cart_forcerefresh

Puedes leer más sobre behaviors de JavaScript en esta guía: JavaScript & Drupal 101 TUTORIAL HANDBOOK TOTAL MAX POWER 2000 (amor al primer behavior), de davidjguru. 

Tags

  • Drupal Commerce
  • JavaScript
  • Drupal behaviors
  • Drupal planet

Comments

El contenido de este campo se mantiene privado y no se mostrará públicamente.
Acerca de formatos de texto

Texto sin formato

  • No se permiten etiquetas HTML.
  • Las direcciones de correos electrónicos y páginas web se convierten en enlaces automáticamente.
  • Saltos automáticos de líneas y de párrafos.

Archivo mensual

  • Enero 2022 (1)
  • Mayo 2021 (2)
  • Abril 2021 (1)
  • Noviembre 2012 (1)
  • Septiembre 2012 (3)
  • Agosto 2012 (3)
  • Junio 2012 (6)

Contenido reciente

Reescribiendo el historial de commits de git para editar el autor y el email de commits pasados
3 years 4 months ago
Drupal JavaScript behavior para destacar líneas de pedido editadas en el carrito de Drupal Commerce
3 years 11 months ago
Analizando el rendimiento de Drupal, WordPress o cualquier aplicación php con DDEV, XHProf y XHGui
4 years ago

Comentarios recientes

I would recommend taking a…
1 year 8 months ago
This looks interesting
1 year 8 months ago
Thanks for the comment
3 years 11 months ago

Blogs que sigo

  • Mateu Aguiló "e0ipso"
  • Gábor Hojtsy
  • Pedro Cambra
  • The Russian Lullaby, davidjguru
  • Can It Be All So Simple
  • Maria Arias de Reyna "Délawen"
  • Matt Glaman
  • Daniel Wehner
  • Jacob Rockowitz
  • Wim Leers
  • Dries Buytaert
Syndicate

Pie de página

  • Drupal.org
  • LinkedIn
  • GitHub
  • Mastodon
  • Twitter
Funciona con Drupal