Dostęp do właściwości modelu MVC z poziomu JavaScript

147

Mam następujący model, który jest zawinięty w moim modelu widoku

public class FloorPlanSettingsModel
{
    public int Id { get; set; }
    public int? MainFloorPlanId { get; set; }
    public string ImageDirectory { get; set; }
    public string ThumbnailDirectory { get; set; }
    public string IconsDirectory { get; set; }
}

Jak uzyskać dostęp do jednej z powyższych właściwości z poziomu JavaScript?

Próbowałem tego, ale otrzymałem „nieokreślony”

var floorplanSettings = "@Model.FloorPlanSettings";
alert(floorplanSettings.IconsDirectory);
Null Reference
źródło
5
Dla jasności, to, co się dzieje, to ustawienie wartości zmiennej JavaScript na wartość zmiennej C # „Model.FloorPlanSettings”, która będzie wartością .ToString () tej klasy (ciąg znaków). Następnie próbujesz zaalarmować właściwość JavaScript o nazwie „IconsDirectory” dotyczącą właśnie utworzonej zmiennej ciągu JavaScript. Otrzymujesz niezdefiniowany, ponieważ ciąg JavaScript nie ma właściwości „IconsDirectory”.
Joel Cochran
Dostarczono kompletny przypadek testowy i wyjaśniono wszystkie scenariusze przypisywania danych modelu do zmiennej javascript,
Rajshekar Reddy
To nie działa poza widokiem (cshtml). tj. w zewnętrznym pliku .js, do którego odwołuje się widok.
Spencer Sullivan

Odpowiedzi:

240

Możesz wziąć cały model po stronie serwera i przekształcić go w obiekt JavaScript, wykonując następujące czynności:

var model = @Html.Raw(Json.Encode(Model));

W twoim przypadku, jeśli chcesz tylko obiekt FloorPlanSettings, po prostu przekaż Encodemetodę tę właściwość:

var floorplanSettings = @Html.Raw(Json.Encode(Model.FloorPlanSettings));
Justin Helgerson
źródło
1
Aby potwierdzić, nie ma potrzeby dodawania; na końcu tego? Ponieważ dostaję monit od VS z informacją, że instrukcja nie została zakończona. Ale kiedy próbuję dodać; kod nie działa
Null Reference
1
Co wiesz, mam ten sam błąd w różnych moich projektach. Po prostu to zignoruj; to Visual Studio próbuje pomóc, ale w tym przypadku jest źle. Wynikowy kod HTML i skrypt, które są wysyłane do przeglądarki, są poprawne.
Justin Helgerson
1
Dla mnie to zadziałało: var myModel = @ {@ Html.Raw (Json.Encode (Model));}
ukryty
1
Nie działa, jeśli model ma wartość początkową (Utwórz stronę zamiast strony Edytuj) i napotkany zostanie komunikat „Błąd odniesienia: Model nie jest zdefiniowany”.
Jack
2
W ASP.Net Core, Json.Serialize ()
Mohammed Noureldin
131

Treść odpowiedzi

1) Jak uzyskać dostęp do danych modelu w bloku kodu Javascript / Jquery w .cshtmlpliku

2) Jak uzyskać dostęp do danych modelu w bloku kodu Javascript / Jquery w .jspliku

Jak uzyskać dostęp do danych modelu w bloku kodu Javascript / Jquery w .cshtmlpliku

Istnieją dwa typy Modelprzypisań zmiennej języka C # ( ) do zmiennej JavaScript.

  1. Przypisanie nieruchomość - Podstawowe typy danych podoba int, string, DateTime(np Model.Name)
  2. Przypisanie obiektu - klasy niestandardowe lub wbudowane (np .: Model, Model.UserSettingsObj)

Przyjrzyjmy się szczegółom tych dwóch zadań.

W pozostałej części odpowiedzi rozważmy poniższy AppUserModel jako przykład.

public class AppUser
{
    public string Name { get; set; }
    public bool IsAuthenticated { get; set; }
    public DateTime LoginDateTime { get; set; }
    public int Age { get; set; }
    public string UserIconHTML { get; set; }
}

A wartości, które przypisujemy temu Modelowi, to

AppUser appUser = new AppUser
{
    Name = "Raj",
    IsAuthenticated = true,
    LoginDateTime = DateTime.Now,
    Age = 26,
    UserIconHTML = "<i class='fa fa-users'></i>"
};

Cesja własności

Użyjmy innej składni do przypisania i obserwujmy wyniki.

1) Bez zawijania przypisania właściwości w cudzysłowie.

var Name = @Model.Name;  
var Age = @Model.Age;
var LoginTime = @Model.LoginDateTime; 
var IsAuthenticated = @Model.IsAuthenticated;   
var IconHtml = @Model.UserIconHTML;  

wprowadź opis obrazu tutaj

Jak widać, istnieje kilka błędów Raji Truesą uważane za zmienne javascript, a ponieważ nie istnieją, jest to variable undefinedbłąd. Tam, gdzie w przypadku zmiennej dateTime błąd jest taki, że unexpected numberliczby nie mogą mieć znaków specjalnych, tagi HTML są konwertowane na nazwy jednostek, aby przeglądarka nie myliła twoich wartości i znaczników HTML.

2) Zawijanie przypisania właściwości w cudzysłowach.

var Name = '@Model.Name';
var Age = '@Model.Age';
var LoginTime = '@Model.LoginDateTime';
var IsAuthenticated = '@Model.IsAuthenticated';
var IconHtml = '@Model.UserIconHTML'; 

wprowadź opis obrazu tutaj

Wyniki są prawidłowe, więc zawijanie przypisania właściwości w cudzysłów daje nam prawidłową składnię. Ale pamiętaj, że liczba Agejest teraz ciągiem, więc jeśli nie chcesz, możemy po prostu usunąć cudzysłowy, a zostanie on wyrenderowany jako typ liczbowy.

3) Używanie, @Html.Rawale bez zawijania go w cudzysłów

 var Name = @Html.Raw(Model.Name);
 var Age = @Html.Raw(Model.Age);
 var LoginTime = @Html.Raw(Model.LoginDateTime);
 var IsAuthenticated = @Html.Raw(Model.IsAuthenticated);
 var IconHtml = @Html.Raw(Model.UserIconHTML);

wprowadź opis obrazu tutaj

Wyniki są podobne do naszego przypadku testowego 1. Jednak użycie @Html.Raw()na HTMLłańcuchu dało nam pewne zmiany. Kod HTML jest zachowywany bez zmiany nazw jednostek.

Z dokumentacji Html.Raw ()

Otacza znaczniki HTML w wystąpieniu HtmlString, aby były interpretowane jako znaczniki HTML.

Ale nadal mamy błędy w innych wierszach.

4) Używanie @Html.Rawi zawijanie go w cudzysłów

var Name ='@Html.Raw(Model.Name)';
var Age = '@Html.Raw(Model.Age)';
var LoginTime = '@Html.Raw(Model.LoginDateTime)';
var IsAuthenticated = '@Html.Raw(Model.IsAuthenticated)';
var IconHtml = '@Html.Raw(Model.UserIconHTML)';

wprowadź opis obrazu tutaj

Wyniki są dobre dla wszystkich typów. Ale nasze HTMLdane są teraz uszkodzone, a to zepsuje skrypty. Problem polega na tym, że 'do zawijania danych używamy pojedynczych cudzysłowów, a nawet dane mają pojedyncze cudzysłowy.

Możemy rozwiązać ten problem za pomocą 2 podejść.

1) użyj podwójnych cudzysłowów, " "aby zawinąć część HTML. Ponieważ dane wewnętrzne mają tylko pojedyncze cudzysłowy. (Upewnij się, że po zawinięciu w cudzysłów nie ma "również danych)

  var IconHtml = "@Html.Raw(Model.UserIconHTML)";

2) Usuń znaczenie znaku w kodzie po stronie serwera. Lubić

  UserIconHTML = "<i class=\"fa fa-users\"></i>"

Zawarcie cesji własności

  • Użyj cudzysłowów dla nienumerycznych typów danych.
  • Nie używaj cudzysłowów dla liczbowego typu danych.
  • Służy Html.Rawdo interpretowania danych HTML bez zmian.
  • Zadbaj o swoje dane HTML, aby albo uniknąć cudzysłowów, co oznacza po stronie serwera, albo użyć innego cytatu niż w danych podczas przypisywania do zmiennej javascript.

Przypisanie obiektu

Użyjmy innej składni do przypisania i obserwujmy wyniki.

1) Bez zawijania przypisania obiektu w cudzysłów.

  var userObj = @Model; 

wprowadź opis obrazu tutaj

Kiedy przypiszesz obiekt ac # do zmiennej javascript .ToString(), zostanie przypisana wartość tego obiektu. Stąd powyższy wynik.

2 Zawijanie przypisania obiektu w cudzysłowie

var userObj = '@Model'; 

wprowadź opis obrazu tutaj

3) Używanie Html.Rawbez cudzysłowów.

   var userObj = @Html.Raw(Model); 

wprowadź opis obrazu tutaj

4) Używając Html.Rawrazem z cudzysłowami

   var userObj = '@Html.Raw(Model)'; 

wprowadź opis obrazu tutaj

Html.RawByło żadnego większego wykorzystania dla nas podczas przypisywania obiektu do zmiennej.

5) Używanie Json.Encode()bez cudzysłowów

var userObj = @Json.Encode(Model); 

//result is like
var userObj = {&quot;Name&quot;:&quot;Raj&quot;,
               &quot;IsAuthenticated&quot;:true,
               &quot;LoginDateTime&quot;:&quot;\/Date(1482572875150)\/&quot;,
               &quot;Age&quot;:26,
               &quot;UserIconHTML&quot;:&quot;\u003ci class=\&quot;fa fa-users\&quot;\u003e\u003c/i\u003e&quot;
              };

Widzimy jakąś zmianę, widzimy, że nasz Model jest interpretowany jako obiekt. Ale mamy te znaki specjalne zamienione na entity names. Również zawijanie powyższej składni w cudzysłów nie ma większego sensu. Po prostu otrzymujemy ten sam wynik w cudzysłowie.

Z dokumentacji Json.Encode ()

Konwertuje obiekt danych na ciąg w formacie JavaScript Object Notation (JSON).

Ponieważ napotkałeś już ten entity Nameproblem przy przypisywaniu własności i jeśli pamiętasz, rozwiązaliśmy go za pomocą Html.Raw. Więc spróbujmy tego. Połączmy Html.RawiJson.Encode

6) Używając Html.Rawi Json.Encodebez cudzysłowów.

var userObj = @Html.Raw(Json.Encode(Model));

Rezultatem jest prawidłowy obiekt JavaScript

 var userObj = {"Name":"Raj",
     "IsAuthenticated":true,
     "LoginDateTime":"\/Date(1482573224421)\/",
     "Age":26,
     "UserIconHTML":"\u003ci class=\"fa fa-users\"\u003e\u003c/i\u003e"
 };

wprowadź opis obrazu tutaj

7) Używanie Html.Rawiw Json.Encodecudzysłowach.

var userObj = '@Html.Raw(Json.Encode(Model))';

wprowadź opis obrazu tutaj

Jak widać, owijanie cudzysłowami daje nam dane JSON

Uwagi dotyczące przypisania obiektu

  • Użyj Html.Rawi Json.Encodew połączeniu, aby przypisać swój obiekt do zmiennej javascript jako obiekt JavaScript .
  • Użyj, Html.Rawa Json.Encodetakże zawiń go, quotesaby uzyskać JSON

Uwaga: jeśli zauważyłeś, że format danych DataTime jest nieprawidłowy. Dzieje się tak, ponieważ, jak wspomniano wcześniej, Converts a data object to a string that is in the JavaScript Object Notation (JSON) formatJSON nie zawiera datetypu. Inne opcje, aby naprawić to, aby dodać kolejną linię kodu do obsługi tego typu sam używając JavaScipt Date () obiektu

var userObj.LoginDateTime = new Date('@Html.Raw(Model.LoginDateTime)'); 
//without Json.Encode


Jak uzyskać dostęp do danych modelu w bloku kodu Javascript / Jquery w .jspliku

Składnia Razor nie ma znaczenia w .jspliku i dlatego nie możemy bezpośrednio użyć naszego modelu w .jspliku. Istnieje jednak obejście.

1) Rozwiązanie wykorzystuje zmienne globalne javascript .

Musimy przypisać wartość do zmiennej javascipt o zasięgu globalnym, a następnie użyć tej zmiennej we wszystkich blokach kodu .cshtmli .jsplikach. Więc składnia byłaby taka

<script type="text/javascript">
  var userObj = @Html.Raw(Json.Encode(Model)); //For javascript object
  var userJsonObj = '@Html.Raw(Json.Encode(Model))'; //For json data
</script>

Mając to na miejscu, możemy użyć zmiennych userObji userJsonObjjak i kiedy potrzebne.

Uwaga: Osobiście nie sugeruję używania zmiennych globalnych, ponieważ jest to bardzo trudne do utrzymania. Jeśli jednak nie masz innej opcji, możesz jej użyć mając odpowiednią konwencję nazewnictwa… coś w rodzaju userAppDetails_global.

2) Użycie function () lub closure Wrap cały kod zależny od danych modelu w funkcji. Następnie wykonaj tę funkcję z .cshtmlpliku.

external.js

 function userDataDependent(userObj){
  //.... related code
 }

.cshtml plik

 <script type="text/javascript">
  userDataDependent(@Html.Raw(Json.Encode(Model))); //execute the function     
</script>

Uwaga: przed powyższym skryptem należy odwołać się do zewnętrznego pliku. W przeciwnym razie userDataDependentfunkcja jest niezdefiniowana.

Należy również zauważyć, że funkcja musi mieć również zasięg globalny. Tak więc w przypadku każdego rozwiązania mamy do czynienia z graczami o zasięgu globalnym.

Rajshekar Reddy
źródło
Czy właściwość Model można zaktualizować w javascript i wysłać do metody akcji kontrolera?
@sortednoun tak, możesz, możesz odesłać zmodyfikowane dane z formularza, lub jeśli nie chcesz przeładowywać strony, możesz skorzystać z AJAX
Rajshekar Reddy
Nie używałem Ajax i właśnie próbowałem zmodyfikować właściwość modelu w javascript. ale po przesłaniu formularza zmiana ta nie została odzwierciedlona w modelu. Robiłem coś takiego: var model = @ Html.Raw (Json.Encode (Model)); model.EventCommand = "zaktualizowana wartość"; Dał mi model poprawnie i zaktualizował wartość, ale po przesłaniu zmiany brakowało w metodzie działania. (Chociaż zrobiłem to samo, używając ukrytej kontrolki Html i powiązałem go z EventCommand i zaktualizowałem jego wartość w javascript. Ale zastanawiasz się, czy można zrobić to samo bezpośrednio z modelem?)
@sortednoun Mam twój punkt widzenia, var model = @Html.Raw(Json.Encode(Model));to utworzy obiekt javascript, model który nie ma połączenia z modelem C #, który przekazujesz do widoku. W rzeczywistości Modelpo wyrenderowaniu widoku nie będzie. Więc formularz w interfejsie użytkownika nie będzie miał pojęcia o zmianach danych obiektu javascript. Musisz teraz przekazać cały zmodyfikowany model do kontrolera za pośrednictwem AJAX lub musisz zaktualizować wartość swoich kontrolek wejściowych w formularzu za pomocą JavaScript.
Rajshekar Reddy
Although I did the same thing using hidden Html control and bound it to EventCommand and updated it's value in javascript. But wondering if could do same directly to model?dla tej instrukcji ... nie ma EventCommand w MVC, jego dla formularzy internetowych, gdzie istnieje połączenie między interfejsem użytkownika a akcjami serwera, w MVC wszystko jest oddzielone. Jedynym sposobem interakcji z kontrolerem jest
użycie
21

spróbuj tego: (przegapiłeś pojedyncze cudzysłowy)

var floorplanSettings = '@Html.Raw(Json.Encode(Model.FloorPlanSettings))';
danmbuen
źródło
1
@JuanPieterse z cytatami daje bez JSONcudzysłowów plik javascript Object. Sprawdź moją odpowiedź w tym samym wątku, aby uzyskać więcej informacji. stackoverflow.com/a/41312348/2592042
Rajshekar Reddy
To nieprawda, rozwiązanie @danmbuen zadziałało w moim przypadku, mam problemy i zawijanie go między pojedyncze cytaty działało jak urok, DZIĘKUJĘ;)
Dimitri
4

U mnie okazało się, że owinięcie modelu własności wokół parenów. Nadal występuje ten sam problem z programem Visual Studio narzekającym na średnik, ale to działa.

var closedStatusId = @(Model.ClosedStatusId);
FROgistics
źródło
0

Jeśli zostanie zgłoszony błąd „ReferenceError: Model is not defined” , możesz spróbować użyć następującej metody:

$(document).ready(function () {

    @{  var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
         var json = serializer.Serialize(Model);
    }

    var model = @Html.Raw(json);
    if(model != null && @Html.Raw(json) != "undefined")
    {
        var id= model.Id;
        var mainFloorPlanId = model.MainFloorPlanId ;
        var imageDirectory = model.ImageDirectory ;
        var iconsDirectory = model.IconsDirectory ;
    }
});

Mam nadzieję że to pomoże...

Murat Yıldız
źródło
0

Wiem, że jest już za późno, ale to rozwiązanie działa idealnie zarówno dla .NET Framework, jak i .NET Core:

@ System.Web.HttpUtility.JavaScriptStringEncode ()

Amer Jamaeen
źródło