ASP.NET MVC Core - controladores de eventos de JavaScript con PartialViews cargadas dinámicamente

votos
2

Tengo este script en mi archivo de vista, el propósito de la misma es para llenar una sección de la misma vista, pero sólo una pequeña parte de ella, que es un div HTML con las clases del panel Bootstrap:

<script type=text/javascript>
    function GetVehicles() {      
                     $.get('@Context.Request.Scheme://@hostname/@controller/GetVehicles', {id: @Model.Id}, function (response) {
                                            $(#tabOutVehicles).html(response);
                                        });
                                    }

function GetMedInfo() {
    $.get('@Context.Request.Scheme://@hostname/@controller/GetMedInfo', {id: @Model.Id}, function (response) {
           $(#tabOutMedInfo).html(response);

    });
}
</script>

Mi visión completa, que muestra la salida generada por el script de arriba:

    @{
        Layout = ~/Views/Shared/_Layout.cshtml;
    }
    <script src=~/js/site.js></script>

        <div class=panel panel-primary>
                                <div class=panel-heading>
                                    <a href=#collapseVehicles class=btn student-dash-btn onclick=GetVehicles() data-toggle=collapse>Vehicles</a>
                                </div>

                                <div id=collapseVehicles class=panel-collapse collapse>
                                    <div id=tabOutVehicles>
                                    </div>
                                </div>
                            </div>

                            <div class=panel panel-primary>
                                <div class=panel-heading>
                                    <a href=#collapseMedInfo class=btn student-dash-btn onclick=GetMedInfo() data-toggle=collapse><strong style=color:white>Medical Info</strong></a>
                                </div>

                                <div id=collapseMedInfo class=panel-collapse collapse>
                                    <div id=tabOutMedInfo>
                                    </div>
                                </div>
                            </div>

<script type=text/javascript>
        function GetVehicles() {      
                         $.get('@Context.Request.Scheme://@hostname/@controller/GetVehicles', {id: @Model.Id}, function (response) {
                                                $(#tabOutVehicles).html(response);
                                            });
                                        }

    function GetMedInfo() {
        $.get('@Context.Request.Scheme://@hostname/@controller/GetMedInfo', {id: @Model.Id}, function (response) {
               $(#tabOutMedInfo).html(response);

        });
    }
    </script>

Al hacer clic en los enlaces dentro de los divs panel de archivos de inicio, el método jQuery golpea mi acción del controlador, devuelve la respuesta, y luego pone la respuesta en el div aplicable (#tabOutMedInfo / #tabOutVehicles). Ambas acciones devuelven vistas parciales. Aquí es lo que mi vista parcial parece, ambos tienen el mismo aspecto a excepción de las del modelo que se diferencian:

@model MyViewModel
    <div class=panel-body>
        <a data-url=@Url.Action(EditMedInfo, Controller, new { id = Model.Id }) data-toggle=ajax-modal data-target=#EditMedInfo class=btn btn-default>Edit</a>

        <div class=form-horizontal>
            <div class=>
                <div class=form-group>
                    <div class=col-md-5 col-sm-5 col-xs-5><label asp-for=Variable class=control-label></label></div>
                    <div class=col-md-7 col-sm-7 col-xs-7>
                        @Html.DisplayFor(item => item.Variable)
                    </div>
                </div>
            </div>
        </div>
    </div>

Cuando se hace clic en el hipervínculo anterior, se supone que para ejecutar código JavaScript que carga un referente para la edición, la cual no está sucediendo, en cambio, no se abre el modal. El código JavaScript se encuentra en mi archivo site.js, que está siendo importado en mi punto de vista principal.

Lo que he intentado:
moví la etiqueta de importación script para mis dos vistas parciales y luego lo borré de mi punto de vista, a continuación, hace que el código JavaScript para funcionar y mostrar mi modal, pero esta solución sólo funcionó durante un tiempo.

Nuevo problema:
A continuación, un nuevo problema comenzó a ocurrir, si se carga la primera vista parcial, y se va a cargar la segunda vista parcial sin cerrar la página Web, hace que site.js a ser cargados en dos ocasiones en la vista, una vez por la primera vista parcial, y una segunda vez por la segunda vista parcial. Con site.js cargar dos veces, de alguna manera hace que mi acción después de ser golpeado dos veces, dando como resultado que los datos se insertan dos veces por una acción posterior.

Entonces me decidí a pasar a mi site.js _Layout.cshtml (lo ideal es como debe ser) y lo intentó de nuevo, de esta manera alrededor causó las vistas parciales para rendir de manera normal, pero una vez más, los modales no se presentó cuando se hace clic en el hipervínculos que se encuentran en las vistas parciales.

Mi teoría:
La manera en que yo entiendo, cuando el jQuery obtener métodos de carga de las vistas parciales, que impide la vista parcial de site.js ver, a pesar de que se ha cargado en mi _Layout.cshtml.

Lo que preferiblemente no quiero cambiar:
no quiero para deshacerse de mis pequeñas conseguir acciones, lo construí como esto para mantener los usuarios tanto como sea posible en una página, y llamando a las acciones de obtener por separado los datos reduce su uso.

¿Estoy cargando site.js correctamente? ¿Por qué no se ven vistas parciales site.js?

Editar:
Este es mi _Layout.cshtml

<!DOCTYPE html>
<html>
<head>
    <meta name=viewport content=width=device-width />
    <title>@ViewBag.Title</title>
    <environment names=Development>
        @*Other scripts omitted *@
        <script src=~/js/site.js asp-append-version=true defer></script>
    </environment>

    <environment names=Staging,Production>
        @*Other scripts omitted *@
        <script src=~/js/site.js asp-append-version=true defer></script>
    </environment>
</head>
<body>
    <div id=modal-placeholder></div>
    @RenderBody()
    @RenderSection(scripts, required: false)
</body>
</html>

Y aquí está el código JavaScript situada en el interior site.js :

$(function () {
    var placeholderElement = $('#modal-placeholder');
    var redirectUrl = ;

    $('a[data-toggle=ajax-modal]').click(function (event) {
        var url = $(this).data('url');
        redirectUrl = window.location.href;

        $.get(url).done(function (data) {
            placeholderElement.html(data);
            placeholderElement.find('.modal').modal('show');
        });
    });

    placeholderElement.on('click', '[data-save=modal]', function (event) {
        event.preventDefault();

        var form = $(this).parents('.modal').find('form');
        var actionUrl = form.attr('action');
        var dataToSend = form.serialize();

        $.post(actionUrl, dataToSend).done(function (data) {
            var newBody = $('.modal-body', data);
            placeholderElement.find('.modal-body').replaceWith(newBody);
            var isValid = newBody.find('[name=IsValid]').val() == 'True';
            if (isValid) {
               placeholderElement.find('.modal').modal('hide');
               window.location.assign(redirectUrl);
               }
            }
        });
    });
});

El JavaScript fue escrito como la de arriba para manejar validación del lado del servidor en los modales, ver el brillante artículo aquí: https://softdevpractice.com/blog/asp-net-core-mvc-ajax-modals/

Publicado el 19/09/2018 a las 17:08
fuente por usuario
En otros idiomas...                            


1 respuestas

votos
3

Cuando 'pegar' el código HTML para el panel en la página una vez regresado de la llamada AJAX, que rompe todos los controladores de eventos existentes. Así que hay que volver a unir los elementos manejador de anclaje. Me gustaría envolver su controlador de eventos dentro de una función, y llamar a esa función tanto al cargar la página inicial y también en el controlador éxito ajax (después de haber pegado el HTML). Suponiendo que está usando jQuery, se vería algo como esto:

function bindAjaxModalButtons() {
    $('[data-toggle="ajax-modal"]').click(function() {
        // ... your event handler code here
    });
}
$(function() {
    bindAjaxModalButtons(); // attaches event handlers on initial page load
});

A continuación, cambiar sus funciones ajax de este modo:

function GetMedInfo() {
    $.get('@Context.Request.Scheme://@hostname/@controller/GetMedInfo', {id: @Model.Id}, function (response) {
        $("#tabOutMedInfo").html(response);
        bindAjaxModalButtons(); // <-- this will attach the event handler to the new buttons    
    });
}

EDIT: ahora que puedo ver su archivo JS, esto es lo que debe ser similar:

$(function () {
    var placeholderElement = $('#modal-placeholder');
    var redirectUrl = "";

    bindAjaxModalButtons();

    placeholderElement.on('click', '[data-save="modal"]', function (event) {
        event.preventDefault();

        var form = $(this).parents('.modal').find('form');
        var actionUrl = form.attr('action');
        var dataToSend = form.serialize();

        $.post(actionUrl, dataToSend).done(function (data) {
            var newBody = $('.modal-body', data);
            placeholderElement.find('.modal-body').replaceWith(newBody);
            var isValid = newBody.find('[name="IsValid"]').val() == 'True';
            if (isValid) {
               placeholderElement.find('.modal').modal('hide');
               window.location.assign(redirectUrl);
               }
            }
        });
    });
});

function bindAjaxModalButtons() {
    var btns = $('a[data-toggle="ajax-modal"]');
    btns.unbind(); // <-- so that existing buttons don't get double-bound
    btns.click(function (event) {
        var url = $(this).data('url');
        redirectUrl = window.location.href;
        var placeholderElement = $('#modal-placeholder');
        $.get(url).done(function (data) {
            placeholderElement.html(data);
            placeholderElement.find('.modal').modal('show');
        });
    });
}
Respondida el 19/09/2018 a las 18:23
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more