asp.net-mvc: symbol „@” razor w pliku js

90

Mam .csHtmlplik -razor z funkcją javascript, która używa funkcji @Url.ContentC # wewnątrz dla adresu URL ajax.
Chcę przenieść tę funkcję do .jspliku, do którego odwołuje się mój widok.

Problem polega na tym, że javascript nie „zna” @symbolu i nie analizuje kodu C #.
Czy istnieje sposób odwoływania się do .jsplików z widoku za pomocą symbolu „@”?

gdoron wspiera Monikę
źródło
2
Może to pomoże (zobacz odpowiedź) stackoverflow.com/questions/7892793/ajax-succes-function
Andriy Khrystyanovich

Odpowiedzi:

87

Możesz użyć data-*atrybutów HTML5 . Załóżmy, że chcesz wykonać jakąś akcję po kliknięciu jakiegoś elementu DOM, takiego jak div. Więc:

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

a następnie w oddzielnym pliku javascript możesz dyskretnie pracować z DOM:

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

W ten sposób możesz mieć czystą separację między znacznikami a skryptem bez konieczności stosowania jakichkolwiek tagów po stronie serwera w plikach javascript.

Darin Dimitrov
źródło
Dzięki. Myślę, że dla wielu wartości może być ból głowy. Po pierwsze pomyślałem, że może to rozwiązać mój problem, ale po spróbowaniu znalazłem tak wiele poleceń w moim kodzie i postanowiłem znaleźć inny sposób.
QMaster
19

Cóż, właśnie znalazłem silnik maszynki do golenia na Nuget, który to robi! Znaczenie rozwiązuje @składnię!
Nazywa się RazorJS .

Nuget pakiet


Aktualizacja 2016:
pakiet nie był aktualizowany przez 5 lat, a link do witryny projektu jest martwy. Nie polecam już ludziom korzystania z tej biblioteki.

gdoron wspiera Monikę
źródło
Możesz się temu przyjrzeć? stackoverflow.com/questions/27702322/…
Coder
Pierwszy link jest uszkodzony
Memet Olsen
@MemetOlsen, rzeczywiście, przepraszam, ale nie mogę znaleźć jego kopii, więc go usunąłem :(
gdoron wspiera Monikę
@gdoron, nie ma problemu. Chciałem tylko poinformować cię o martwym łączu. Jak już wspomniałeś, pakiet nie był aktualizowany przez 5 lat, więc prawdopodobnie i tak jest złym pomysłem.
Memet Olsen
10

Jednym ze sposobów rozwiązania tego problemu jest:

Dodanie częściowego widoku z funkcjami javascript do widoku.
W ten sposób możesz użyć @symbolu, a wszystkie javascriptfunkcje są oddzielone od widoku.

gdoron wspiera Monikę
źródło
9

Masz dwie możliwości:

  • Użyj wartości jako parametru w funkcji i połącz w widoku
  • Utwórz przestrzeń nazw (zamiast zmiennej poziomu publicznego, która jest uważana za złą praktykę w JS) i ustaw tę wartość na górze strony, a następnie użyj jej w swoim js

Na przykład:

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

A potem twoim zdaniem ustaw to:

MyCompany.MyProject.MyVariable = @....

AKTUALIZACJA

Możesz się zastanawiać, że żadna z nich nie jest dobra ze względu na połączenie, cóż, to prawda, łączysz js i widok. Dlatego skrypty muszą być nieświadome lokalizacji, w której działają, więc jest to objaw nieoptymalnej organizacji plików.

W każdym razie istnieje trzecia opcja, aby utworzyć silnik widoku i uruchomić pliki js na maszynce do golenia i odesłać wyniki. Jest to czystsze, ale znacznie wolniejsze, więc też nie jest zalecane.

Aliostad
źródło
1
+1 Robię pierwszą metodę. Wywołaj funkcję inicjalizacyjną z poziomu swojego widoku, przekazując wszystkie wymagane dane.
Richard Dalton
Dzięki, drugie podejście nie jest złym sprzężeniem między widokiem a plikiem js? Czy masz lepszy sposób?
gdoron wspiera Monikę
Oba są sprzężeniem. Nie ma możliwości odłączenia, chyba że napiszesz silnik widoku do przetwarzania plików js przed renderowaniem. Zobacz moje aktualizacje.
Aliostad
co z tą drogą, którą zaproponowałem? stackoverflow.com/questions/7902213/ ...
gdoron wspiera Monikę
Brzmi dobrze. Moje +1. Widok częściowy lub pełny niczego nie zmienia. To wszystko jest sprzężeniem z js.
Aliostad
7

Aby @umieścić zmienną w pliku .js, musisz użyć zmiennej globalnej i ustawić wartość tej zmiennej z widoku mvc, który korzysta z tego pliku .js.

Plik JavaScript:

var myValue;

function myFunc() {
  alert(myValue);
}

Plik widoku MVC:

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

Po prostu upewnij się, że wszelkie wywołania Twojej funkcji następują PO ustawieniu wartości przez widok.

Joel Etherton
źródło
1
a co z przekazaniem bezpośrednio myValue jako parametru do funkcji? Wolę mieć wyraźne wywołanie z param niż poleganie na globals, jednak nie jestem zbytnio zainteresowany JavaScriptem, więc może brakuje mi jakiegoś ważnego aspektu posiadania globalnego.
BigMike
@BigMike: Z pewnością do zaakceptowania. Metoda, którą przedstawiłem powyżej, po prostu sprawia, że ​​zmienna jest dostępna dla wielu funkcji jednocześnie, ale używanie parametrów jest równie dobre.
Joel Etherton
dzięki za wyjaśnienie. Byłoby wspaniale mieć jakąś wersję modelu obiektu js automatycznie (poprzez Attributes w klasie modelu będzie świetnie), to po prostu doda wzorzec i rozwiązanie w pełni uwzględniające przestrzeń nazw. Myślę, że dużym problemem byłoby wstrzyknięcie kodu w wygenerowanym html wysłanym do przeglądarki (bezpośrednio przez tag <script>). Myślę, że przeprowadzę na tym trochę eksperymentów, gdy tylko mój obecny projekt się zakończy.
BigMike
@BigMike: Powinno to być dość łatwe do osiągnięcia przy użyciu klasy DataContractJsonSerializer ( msdn.microsoft.com/en-us/library/… ). Stworzyłoby to wersję JSON twojej klasy, którą można byłoby przeanalizować w widoku.
Joel Etherton
4

Prawdopodobnie nie jest to właściwe podejście. Rozważenie rozdzielenia obaw. Powinieneś mieć data injectorna swojej JavaScriptklasie i która jest w większości przypadków danymi JSON.

Utwórz plik JS w swoim scriptfolderze i dodaj to odniesienie do swojegoView

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

Rozważ teraz JavaScriptdosłowną klasę w swoim yourJsFile.js:

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

Zadeklaruj również klasę

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

Teraz Actionzrób to:

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

I z twojego punktu widzenia:

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

<script type="text/javascript">
    contentSetter.loadData('@Json.Encode((ContentData) ViewData["contentData"])');
    contentSetter.setContentA();
    contentSetter.setContentB();
</script>
Abdul Munim
źródło
Ładny! ale myślę, że to zbyt skomplikowane ... co myślisz o mojej odpowiedzi? stackoverflow.com/questions/7902213/… . tak przy okazji masz błąd kopiowania wklejania w setContentB, napisałeś contentAData. podziękować!
gdoron wspiera Monikę
1
@gdoron Uwierz mi, zarządzanie klasami JS i rozważanie separacji ratuje życie, gdy masz duży projekt
Abdul Munim
2

Zwykle pakuję JS, potrzebując dostępu do właściwości modelu, w funkcje, a następnie przekazuję @something w widoku. Na przykład

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

w widoku dodaję wywołanie funkcji za pośrednictwem (tylko przykład):

<input type='button' onclick="MyFunction('@Model.PropertyNeeded')" />
BigMike
źródło
1

Myślę, że utknąłeś z koniecznością umieszczenia tego kodu JS w widoku. O ile wiem, parser Razor nie będzie przeglądał plików .js, więc wszystko, co masz @, nie zadziała. PLus, jak zauważyłeś, sam Javascript nie lubi tej @postaci kręcącej się bez powodu, inaczej niż, powiedzmy, w ciągu.

Jason Evans
źródło