asp.net-mvc: símbolo de razor '@' en el archivo js


90

Tengo un .csHtmlarchivo -razor con una función javascript que usa la @Url.Contentfunción C # adentro para la URL ajax.
Quiero mover esa función a un .jsarchivo referenciado desde mi vista.

El problema es que javascript no "conoce" el @símbolo y no analiza el código C #.
¿Hay alguna forma de hacer referencia a los .jsarchivos desde la vista con el símbolo "@"?


Respuestas:


87

Puede utilizar data-*atributos HTML5 . Supongamos que desea realizar alguna acción cuando se hace clic en algún elemento DOM, como un div. Entonces:

<div id="foo" data-url="@Url.Content("~/foobar")">Click me</div>

y luego, en su archivo javascript separado, podría trabajar discretamente con el DOM:

$('#foo').click(function() {
    var url = $(this).data('url');
    // do something with this url
});

De esta manera, podría tener una separación pura entre el marcado y el script sin que nunca necesite etiquetas del lado del servidor en sus archivos javascript.


Gracias. Creo que para múltiples valores puede ser un dolor de cabeza. En primer lugar, pensé que podía resolver mi problema, pero después de intentarlo, encontré tantas referencias en mi código y decidí buscar otra forma.
QMaster

19

¡Bueno, acabo de encontrar un motor de afeitar en nuget que lo hace! ¡El significado resuelve la @sintaxis!
Su nombre es RazorJS .

El paquete Nuget


Actualización de 2016:
el paquete no se actualizó durante 5 años y el enlace del sitio del proyecto está inactivo. Ya no recomiendo a la gente que use esta biblioteca.



El primer enlace está roto
Memet Olsen

@MemetOlsen, de hecho, lo siento, pero no puedo encontrar una copia, así que lo
eliminé

@gdoron, no hay problema. Solo quería informarle sobre el enlace muerto. Como ha dicho, el paquete no se actualizó durante 5 años, por lo que probablemente sea una mala idea usarlo de todos modos.
Memet Olsen

10

Una forma de abordar el problema es:

Agregar una vista parcial con las funciones de JavaScript a la vista.
De esta forma puede utilizar el @símbolo y todas sus javascriptfunciones están separadas de la vista.


9

Tienes dos opciones:

  • Utilice el valor como parámetro en la función y cableado en la vista
  • Cree un espacio de nombres (en lugar de una variable de nivel público que se considera una mala práctica en JS) y establezca este valor en la parte superior de la página y luego úselo en su js

Por ejemplo:

 var MyCompany = 
 {
   MyProject: {
                  MyVariable:""
               }
  };

Y luego, en su vista, configúrelo:

MyCompany.MyProject.MyVariable = @....

ACTUALIZAR

Quizás se pregunte que ninguno es bueno debido al acoplamiento, bueno, es cierto, está acoplando js y view. Es por eso que los scripts deben ser ajenos a la ubicación en la que se ejecutan, por lo que es un síntoma de una organización no óptima de los archivos.

De todos modos, hay una tercera opción para crear un motor de visualización y ejecutar los archivos js contra la maquinilla de afeitar y enviar los resultados. Esto es más limpio pero mucho más lento, por lo que tampoco se recomienda.


1
+1 Yo hago el primer método. Llame a una función de inicialización desde su vista pasando todos los datos que necesita.
Richard Dalton

Gracias, ¿el segundo enfoque no es un mal acoplamiento entre la vista y el archivo js? ¿Tienes una forma mejor?
gdoron apoya a Monica el

Ambos se acoplan. No hay forma de desacoplar a menos que escriba un motor de vista para procesar archivos js antes de renderizar. Ver mis actualizaciones.
Aliostad


Suena bien. Mi +1. Ya sea vista parcial o completa, no cambia nada. Todo es vista de acoplamiento con js.
Aliostad

7

Para obtener la @variable en su archivo .js, tendrá que usar una variable global y establecer el valor de esa variable desde la vista mvc que está haciendo uso de ese archivo .js.

Archivo JavaScript:

var myValue;

function myFunc() {
  alert(myValue);
}

Archivo de vista MVC:

<script language="text/javascript">
    myValue = @myValueFromModel;
</script>

Solo asegúrese de que cualquier llamada a su función ocurra DESPUÉS de que la vista haya establecido el valor.


1
¿Qué hay de pasar directamente myValue como parámetro a la función? Prefiero tener llamadas explícitas con param que confiar en globales, sin embargo, no estoy tan interesado en javascript, por lo que es posible que me esté perdiendo algún aspecto importante de tener un archivo global.
BigMike

@BigMike: Ciertamente aceptable. El método que expuse anteriormente simplemente hace que la variable esté disponible para múltiples funciones simultáneamente, pero usar parámetros es igual de bueno.
Joel Etherton

gracias por la aclaración. Sería genial tener algún tipo de versión de objeto js del modelo automáticamente (a través de Atributos en la clase de modelo será genial), esto solo agregará un patrón y una solución de variable totalmente consciente del espacio de nombres. Supongo que el gran problema sería cómo inyectar el código en el html generado enviado al navegador (directamente a través de la etiqueta <script>). Creo que realizaré algunos experimentos sobre esto tan pronto como termine mi proyecto actual.
BigMike

@BigMike: Esto debería ser bastante fácil de lograr utilizando la clase DataContractJsonSerializer ( msdn.microsoft.com/en-us/library/… ). Crearía una versión JSON de su clase que podría analizarse en la vista.
Joel Etherton

4

Probablemente este no sea el enfoque correcto. Considerando la separación de preocupaciones. Debería tener un data injectoren su JavaScriptclase y, en la mayoría de los casos, los datos sonJSON .

Cree un archivo JS en su scriptcarpeta y agregue esta referencia a suView

<script src="@Url.Content("~/Scripts/yourJsFile.js")" type="text/javascript"></script>

Ahora, considere una JavaScriptclase literal en su yourJsFile.js:

var contentSetter = {
    allData: {},
    loadData: function (data) {
        contentSetter.allData = eval('(' + data + ')');
    },
    setContentA: function () {
        $("#contentA").html(allData.contentAData);
    },
    setContentB: function () {
        $("#contentB").html(allData.contentAData);
    }
};

También declara una clase

public class ContentData
{
    public string ContentDataA { get; set }
    public string ContentDataB { get; set }
}

Ahora, de tu Actionhaz esto:

public ActionResult Index() {
    var contentData = new ContentData();
    contentData.ContentDataA = "Hello";
    contentData.ContentDataB = "World";
    ViewData.Add("contentData", contentData);
}

Y desde tu punto de vista:

<div id="contentA"></div>
<div id="contentB"></div>

<script type="text/javascript">
    contentSetter.loadData('@Json.Encode((ContentData) ViewData["contentData"])');
    contentSetter.setContentA();
    contentSetter.setContentB();
</script>

¡Agradable! pero creo que es demasiado complicado ... ¿qué opinas de mi respuesta? stackoverflow.com/questions/7902213/… . por cierto, tiene un error de copiar y pegar en setContentB que escribió contentAData. ¡gracias!
gdoron apoya a Monica el

1
@gdoron Créame, administrar las clases de JS y considerar la separación es un salvavidas cuando tiene un gran proyecto
Abdul Munim


2

Por lo general, envuelvo JS que necesita acceso a las propiedades del modelo, en funciones y luego paso el @algo en la vista. Por ejemplo

<script type="text/javascript">
function MyFunction(somethingPresentInTheView) {
  alert(somethingPresentInTheView);
}
</script>

en la vista agrego la invocación de la función a través de (solo un ejemplo):

<input type='button' onclick="MyFunction('@Model.PropertyNeeded')" />

1

Creo que estás atrapado en tener que poner ese código JS en la Vista. El analizador de Razor, hasta donde yo sé, no mira los archivos .js, por lo tanto, cualquier cosa que tenga que use @no funcionará. ADEMÁS, como ha visto, a Javascript en sí no le gusta que este @carácter merodee sin ninguna razón, aparte de, digamos, en una cadena.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.