2013-03-08 9 views
10

Mam listę użytkowników, które przechodzę z kontrolera do mojego widoku przy użyciu worka widoku. Teraz muszę mieć możliwość przekazania tej samej listy do javascript na stronie. Mogę zrekonstruować listę za pomocą pętli foreach:Lista przechodzących z MVC ViewBag do JavaScript

@foreach (var item in ViewBag.userList) //Gets list of users passed from controller and adds markers to the map 
{ 
    var userLat = item.LastLatitude; 
    var userLon = item.LastLongitude; 
    var _userId = item.Id; 

    <script>array.push({"userId":"'@_userId'","userLat":"'@userLat'","userLon":"'@userLon'"});</script> 
} 

to jednak wydaje się bałagan i podejście wymaga dużo przeróbek czy zmian. Wiem, że są podobne posty na przepełnieniu stosu, ale wiele z nich używa poprzedniej wersji MVC i ta sama składnia nie ma zastosowania. Jakieś pomysły?

Odpowiedz

20

Można to zrobić w pojedynczej i bezpiecznej linii kodu przy użyciu parsera JSON. Absolutnie nigdy nie należy ręcznie budować JSON-a z niektórymi ciągami konkatenacji i takimi, jak próbowaliście zrobić w tym przykładzie. Nie trzeba również pisać żadnych pętli.

Oto poprawny sposób, aby to zrobić:

<script type="text/javascript"> 
    var array = @Html.Raw(
     Json.Encode(
      ((IEnumerable<UserModel>)ViewBag.userList).Select(user => new 
      { 
       userId = user.Id, 
       userLat = user.LastLatitude, 
       userLon = user.LastLongitude 
      }) 
     ) 
    ); 

    alert(array[0].userId); 
</script> 

Wygenerowany HTML będzie wyglądać dokładnie tak, jak można się spodziewać:

<script type="text/javascript"> 
    var array = [{"userId":1,"userLat":10,"userLon":15}, {"userId":2,"userLat":20,"userLon":30}, ...]; 
    alert(array[0].userId); 
</script> 

Oczywiście następny stopień poprawy w tym kodzie jest pozbyć z ViewCrap i użyj mocno wpisanego modelu widoku.

+0

Dzięki za szybką i szczegółową odpowiedź! Ale pojawia się następujący komunikat: "Nie można użyć wyrażenia lambda jako argumentu dla operacji dynamicznie wywoływanej ..." bez części IEnumerable. Po dodaniu tej części dostaję również komunikat "Argumenty typu dla metody ... nie można wywnioskować z użycia". Dziękuję za pomoc i przepraszam, jeśli jest to błąd debiutanta. p.s. Używam modelu widoku do czegoś innego na tej stronie, dlatego używam worka widoku. – Matt

+0

Model widoku to klasa zaprojektowana specjalnie w celu spełnienia wymagań Twojego widoku. W takim przypadku twój widok musi wygenerować ten dynamiczny javascript. Tak więc twój model widoku powinien zawierać właściwość kolekcji typu 'IEnumerable '. A następnie po prostu zamień całą obsadę na 'Model.Users.Select (...)'.Jeśli opuścisz słabo napisaną ViewBag, będziesz musiał rzucić ją do właściwego 'IEnumerable ' typu. –

+0

OK Szybko zmodyfikowałem stronę i użyłem modelu View i zadziałało. Musiałem również odnieść się do innej z twoich odpowiedzi http://stackoverflow.com/questions/12111729/razor-javascript-and-trailing-semicolon, nie wiedziałem o tym błędzie w VS2012. Dzięki za wspaniałą i pouczającą odpowiedź! – Matt

2

Inną opcją, może być utworzenie nowej akcji w kontrolerze, zwracając JsonResult. Ten wynik json może zwrócić twoją listę. Na swojej stronie możesz wywołać akcję za pomocą jquery i używać jej z tego miejsca.

public ActionResult GetMyList() 
{ 
    var list = GetMyUserList(); 

    return Json(new { userlist = list }, JsonRequestBehaviour.AllowGet); 
} 
+0

Dzięki za napiwek, też to wypróbuję :) – Matt

1

@Darin Dimitrov odpowiedź jest na miejscu. Chciałbym tylko dodać, jeśli ktokolwiek przechodzi model, a nie widok.

<script type="text/javascript"> 
var array = @Html.Raw(Json.Encode(
      Model.YourModel.Select(_ => new { 
       id = _.Id, 
       text = _.Name 
      }) 
     )) 

Mój przypadek użycia był specyficzny dla select2. Można wtedy po prostu przekazać tablicę z danymi: atrybut

$("#storeSelect").select2({ 
     data: array, 
     placeholder: "Select something" 
}); 
</script> 

ViewModel

public class YourViewModel 
    { 
    public IEnumarable<YourPoco> YourPocos { get; set; } 
    } 

Controller

public class YourController : Controller 
{ 
    public ActionResult Index() 
    { 
     YourViewModel vm = new YourViewModel{ 
      // Using Dependancy injection 
      YourPocos = yourRepo.GetYourPocos(); 
     }; 
     return View("Index", "_Layout",vm); 
    } 
} 

Zdaję sobie sprawę, to odpowiedź może być zbędny, ale jest po raz pierwszy używam Json.Encode i przekazywanie wartości modelu do rozszerzenia jquery. To dla mnie jest zbyt fajne. W pewnym stopniu tworzy ogromną rozciągliwość na to, co w przeciwnym razie byłby @htmlhelper