Vista previa instantánea de imágenes en formularios Laravel

Este snippet de JavaScript muestra una vista previa instantánea cuando el usuario selecciona una nueva imagen en un formulario, sin necesidad de enviar el formulario.

Problema que resuelve: Cuando un usuario edita un registro y cambia una imagen, normalmente sigue viendo la miniatura de la imagen antigua mientras que el nombre del archivo muestra la nueva selección, lo que resulta confuso.

Opción 1: JavaScript en archivo separado (public/js)

document.addEventListener('DOMContentLoaded', function() {
    const inputImagen = document.getElementById('imagen');
    if (inputImagen) {
        inputImagen.addEventListener('change', function(e) {
            const file = e.target.files[0];
            if (file) {
                const reader = new FileReader();
                reader.onload = function(event) {
                    const previewImagen = document.getElementById('preview-imagen');
                    if (previewImagen) {
                        previewImagen.src = event.target.result;
                    }
                };
                reader.readAsDataURL(file);
            }
        });
    }
});

Implementación: Guarda este código en public/js/imagen-preview.js e inclúyelo en tu vista con:

<script src="{{ asset('js/imagen-preview.js') }}"></script>

Opción 2: Directamente en la vista Blade

@section('scripts')
<script>
    document.addEventListener('DOMContentLoaded', function() {
        document.getElementById('imagen').addEventListener('change', function(e) {
            const file = e.target.files[0];
            if (file) {
                const reader = new FileReader();
                reader.onload = function(event) {
                    document.getElementById('preview-imagen').src = event.target.result;
                };
                reader.readAsDataURL(file);
            }
        });
    });
</script>
@endsection

Implementación: Añade este código al final de tu archivo Blade y asegúrate de que tu layout tenga una sección @yield('scripts').

Opción 3: Con Laravel Mix

Guarda el código en resources/js/imagen-preview.js:

export function setupImagePreviews() {
    const inputImagen = document.getElementById('imagen');
    if (inputImagen) {
        inputImagen.addEventListener('change', function(e) {
            const file = e.target.files[0];
            if (file) {
                const reader = new FileReader();
                reader.onload = function(event) {
                    const previewImagen = document.getElementById('preview-imagen');
                    if (previewImagen) {
                        previewImagen.src = event.target.result;
                    }
                };
                reader.readAsDataURL(file);
            }
        });
    }
}

Importa la función en resources/js/app.js:

import { setupImagePreviews } from './imagen-preview';

document.addEventListener('DOMContentLoaded', function() {
    setupImagePreviews();
});

Configura webpack.mix.js:

const mix = require('laravel-mix');

mix.js('resources/js/app.js', 'public/js');

Compila los assets:

npm run dev

Incluye en tu vista:

<script src="{{ mix('js/app.js') }}"></script>

Nota: No olvides añadir un elemento <img id="preview-imagen"> en tu HTML para mostrar la vista previa.

Vista previa instantánea de imágenes en formularios Laravel Leer más »

Problema con condicionales en Toolset Views

Problema

Cuando trabajamos con condicionales en Toolset Views, es común encontrarnos con problemas de sintaxis que impiden que nuestras condiciones funcionen correctamente. En este caso específico, estaba intentando aplicar un estilo diferente al último elemento de un bucle, comparando el índice actual ([wpv-loop-index]) con el número total de elementos ([wpv-post-count]).
El código original tenía estos problemas:

Uso incorrecto de operadores de comparación (le en lugar de lt para «menor que»)
Uso de comillas simples alrededor de los shortcodes de Toolset, lo que impedía su correcta evaluación

Solución

La solución consiste en:

[wpv-noautop]
[wpv-layout-start]
  [wpv-items-found]
    <!-- wpv-loop-start -->
	<wpv-loop>
		<!-- el nombre de membres és inferior al total -->
        [wpv-conditional if="( '[wpv-loop-index]' lt '[wpv-post-count]')"]
                [wpv-post-title], 
        [/wpv-conditional]
  
        <!-- el nombre de membres és inferior al total-->
        [wpv-conditional if="( '[wpv-loop-index]' eq '[wpv-post-count]')"]
                [wpv-post-title]
        [/wpv-conditional] 
	</wpv-loop>
	<!-- wpv-loop-end -->
  [/wpv-items-found]
[wpv-layout-end]

[/wpv-noautop]

Explicación de los shortcodes utilizados

[wpv-loop-index]

Este shortcode devuelve el número de iteración actual dentro del bucle de la vista. Comienza en 1 para el primer elemento y se incrementa en cada iteración. Es extremadamente útil cuando necesitas:

  • Aplicar estilos diferentes a elementos específicos (como el primero o el último)
  • Crear diseños basados en la posición (por ejemplo, alternar colores)
  • Implementar paginación manual o contadores personalizados

[wpv-post-count]

Este shortcode devuelve el número total de elementos (generalmente posts) que coinciden con los criterios de filtrado de la vista. Es útil para:

  • Saber cuántos elementos hay en total
  • Identificar el último elemento del bucle
  • Crear indicadores de progreso (Ej: «Mostrando 3 de 10»)
  • Aplicar lógica condicional basada en la cantidad total

Uso combinado

Cuando combinas ambos shortcodes con operadores condicionales, puedes crear diseños avanzados y personalizados según la posición relativa de cada elemento.

  • Operadores condicionales en Toolset
  • Para referencia, estos son los operadores condicionales más comunes en Toolset:
  • eq: igual a (equal)
  • neq: no igual a (not equal)
  • lt: menor que (less than)
  • le: menor o igual que (less than or equal)
  • gt: mayor que (greater than)
  • ge: mayor o igual que (greater than or equal)

Visto en Toolset

Problema con condicionales en Toolset Views Leer más »

Toolset: Select2

jQuery(document).ready(function() {
    jQuery('#desplegabledir select').select2();
});

Añadir select2 en un desplegable de toolset. Els desplegable tiene id y css class desplegabledir.

<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>

Toolset: Select2 Leer más »

Showing posts in calendar view based on start of the day

add_shortcode('ts_day_week_start', function($atts){
    $atts = shortcode_atts( array(
        'day' => 'Monday',
    ), $atts);
    $res = strtotime('last ' . $atts['day']);
    if(date('l') == $atts['day']){
        $res = strtotime('this ' . $atts['day']);
    }
    return $res;
});
 
 
add_shortcode('ts_day_week_end', function($atts){
    $atts = shortcode_atts( array(
        'day' => 'Monday',
    ), $atts);
    $res = strtotime('last ' . $atts['day']);
    if(date('l') == $atts['day']){
        $res = strtotime('this ' . $atts['day']);
    }
    $res = strtotime("tomorrow", $res) - 1;
    return $res;
});
[wpv-view name="schedule-view" cached="off" tsstart="[ts_day_week_start day='Friday']" tsend="[ts_day_week_end day='Friday']"]

Visto en Toolset

Showing posts in calendar view based on start of the day Leer más »

Toolset: Update Title and Slug of Post with Custom Field Content when post saves in the WordPress backend

add_filter( 'wp_insert_post_data' , 'set_issue_title' , '10', 3 );
  
function set_issue_title( $data , $postarr ) {
if ( 'my_post_type' != $data['post_type'] )
return $data;
  
$post_title = $data['post_title'];
  
if ( ! $post_title ) {
  
$issue_number = trim( $_POST['wpcf']['single1'] ); 
$issue_type = trim( $_POST['wpcf']['single2']);
  
$issue_title = $issue_type . ' - ' . $issue_number;
$post_slug = sanitize_title_with_dashes ($issue_title,'','save');
$post_slugsan = sanitize_title($post_slug);
  
$data['post_title'] = $issue_title;
$data['post_name'] = $post_slugsan;
  }
  
return $data;
}

Visto en https://toolset.com/forums/topic/use-custom-field-to-set-title-slug/

Revisar este otro post: https://toolset.com/forums/topic/use-custom-fields-to-set-post-title-and-post-slug/

Toolset: Update Title and Slug of Post with Custom Field Content when post saves in the WordPress backend Leer más »

Toolset: Auto Generate Post Title and Name/Slug by Combining Other Fields

add_action('cred_save_data', 'build_post_title', 10, 2);
function build_post_title($post_id, $form_data) {
 
if ($form_data['id']==9999) {
$field1 = get_post_meta($post_id, 'wpcf-street_address', true);
$field2 = get_post_meta($post_id, 'wpcf-city_address', true);
$term_list = wp_get_post_terms($post_id, 'state-address', array("fields" => "names"));
$terms = join("-",$term_list);
$field4 = get_post_meta($post_id, 'wpcf-zip_address', true);
 
$post_title=$field1.'-'.$field2.'-'.$terms.'-'.$field4;
$slug = sanitize_title($post_title);
wp_update_post(array('ID'=>$post_id, 'post_title'=>$post_title,'post_name' => $slug));
}
}

Visto en https://toolset.com/forums/topic/auto-generate-post-title-and-nameslug-by-combining-other-fields/

Toolset: Auto Generate Post Title and Name/Slug by Combining Other Fields Leer más »

Toolset: Author frontend filtering with views and ajax

add_shortcode("list-of-authors", "list_of_authors");
function list_of_authors() {
  $out = '<option value="">All</option>';
  $users = get_users();
  foreach ($users as $user) {
    $selection = (isset($_GET['author-filter']) ? $_GET['author-filter']: '');
    $out .= '<option ' . selected($user->ID, $selection, false) . ' value="' . $user->ID . '">' . $user->display_name . '</a>';
  }
  return $out;
<select name="author-filter" class="js-wpv-filter-trigger">[list-of-authors]</select>

Visto en: https://toolset.com/forums/topic/author-frontend-filtering-with-views-and-ajax/

Toolset: Author frontend filtering with views and ajax Leer más »

Scroll al inicio