ASP.NET Lista w modelu, obsługa po stronie widoku

0

Hej, mam mały problem z obsługą listy w ASP.NET.

 
 public class Customer
    {
        public int Id { get; set; }
        public string FirstName { get; set; }        
        public string LastName { get; set; }
        public virtual List<CustomerAddress> Addresses { get; set; }

    }

dla takiej klasy bez problemu mogę sobie wylistować te adresy w widoku

 @foreach(var address in model.Addresses
{
 //tutaj jakies wypisywanie strasznych danych 
}
 

Ale co mam zrobić gdybym chciał dodać do modelu nowy adres ale nie zapisywać go jeszcze do bazy, najlepiej bez przeładowywania strony ?

Próbowałem użyć PartialView i Ajax.BeginForm i nie bardzo to chce zadziałać.
Pamiętam, że kiedyś miałem podobny problem i rozchodziło się o wersje jakiejś biblioteki do jQuery ale to jest bez sensu za każdym razem tego szukać.

Chciałbym potem, żeby lista którą tutaj posiadam została też wysłana do kontrolera w modelu.

Pozdrawiam

0

Ja bym polecał zrobić metodę w kontrolerze, która przyjmowała by w parametrze nowy adres i wywoływać ją ajaxem. Samą Listę adresów trzymałbym w sesji i ta metoda dodawała by nowy adres do listy z sesji. W momencie kiedy chciałbyś zrobić zapis (nie do końca wiem jak to jest z nHibernate) wywoływał byś metodę która ci to zapisze. W Entity wymagane jest użycie dbContext.SaveChanges(), jeżeli nHibernate "sam" zapisuje to może wystarczy zrobić klasę zbliżoną do modelu adres i na niej operować, a przy zapisie po prostu przepisać dane na klasę nHibernate.

0

A wiesz może jak przekazać dane z PartialView do modelu? Bo ogólnie nie ważne gdzie dam submita to danych z listy tam nie ma (Count = 0)

1

musisz w partial View dodać hiddenFor na elementy listy, ponieważ przesyłając model jest on dostępny tylko dla razora a klient dostaje już obrobioną wersję, co oznacza że te dane tracisz. Coś czuje że słowami ciężko mi będzie to wytłumaczyć więc dam ci mały przykład. Ogólnie jak byś nie użył hiddenFor to wartość paramaetru model w metodzie Post About też byłaby nullem.

Kontroler:

 public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            
            List<string> model = new List<string>();
            model.Add("jeden");
            model.Add("dwa");
            model.Add("trzy");



            return View(model);
        }

        [HttpPost]
        public ActionResult About(List<string> model)
        {

            return View(model);
        }
 

CShtml

@model List<string>
@{
    ViewBag.Title = "About";
}
<h2>@ViewBag.Title.</h2>
<h3>@ViewBag.Message</h3>

<p>Use this area to provide additional information.</p>



@using (Html.BeginForm("About", "Home", FormMethod.Post))
{
    for (int i = 0; i < Model.Count; i++)
    {
        @Html.HiddenFor(model => Model[i])
    }

    
    <input type="submit" value="Wyślij"/>
}

 

W załączniku masz efekt hiddena. Chodzi o to że robi ukryte inputy i później jak robisz submit to z nich zczytuje wartości.

0

No tak ale tym sposobem nie jestem w stanie submitować zawartości listy z resztą modelu na raz

1

Lista może być elementem Modelu, i wtedy będziesz mógł wysyłać razem z resztą. Mi osobiście się wydaje że tą listę powinieneś przechowywać w sesji. Elementy dodawać ajaxem wywołując odpowiednią metodę kontrolera i przy "głównym" submicie pobrać listę z sesji. później postaram się podesłać przykład

0

Dzięki, skoro tak wymagają dobre praktyki to sam to ogarnę. Dzięki za rady ;)

0

Już zacząłem pisać to już wyślę :) Da się zrobić inaczej to zależy czego potrzebujesz itd, itp. Ogólnie możesz też po dodaniu nowego wpisu do listy za pomocą JS dopisywać nowego inputa analogicznie do tego co powstało za pomocą hiddenFor. Kontroler to zinterpretuje jako kolejny element listy. Jednak ja przedstawiam pomysł z Session + ajax

View Model:

    public class PersonViewModel
    {
        public string Imie { get; set; }
        public int Wiek { get; set; }
    }

    public class Zwierzak
    {
        public string Rasa { get; set; }
        public string Imie { get; set; }
    }

Kontroler Home:

  public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            if (Session["Zwierzaczki"] == null)
            {
                Session["Zwierzaczki"] = new List<Zwierzak>();
            }

            var model = new PersonViewModel()
            {
                Imie = "Jan",
                Wiek = 44
            };

            return View(model);
        }

        [HttpPost]
        public ActionResult About(PersonViewModel model)
        {
            ViewBag.Message = "Your application description page.";

            var tmp = Session["Zwierzaczki"] as List<Zwierzak>;


            return View(model);
        }

        public void AddToSession(Zwierzak zwierzak)
        {
            var tmp = Session["Zwierzaczki"] as List<Zwierzak>;
            tmp?.Add(zwierzak);
            Session["Zwierzaczki"] = tmp;
        }
 

Widok Home:

@using MVC_TEST.Models
@model MVC_TEST.Models.PersonViewModel

@{
    var listaZwierzakow = Session["Zwierzaczki"] as List<Zwierzak>;
}

@using (Html.BeginForm("About", "Home", FormMethod.Post))
{
    <div style="margin-top: 60px;">
        <div class="row">
            @Html.TextBoxFor(model => model.Imie)
            @Html.TextBoxFor(model => model.Wiek)
        </div>
        <div class="row" style="margin-top: 20px;">
            <div class="col-sm-3" id ="zwierzakiTabelka">
                @foreach (var item in listaZwierzakow)
                {
                    <div class="row ">
                        <div class="col-sm-6">
                            @item.Imie
                        </div>
                        <div class="col-sm-6">
                            @item.Rasa
                        </div>
                    </div>
                }
            </div>
            <div class="col-sm-3">
                <input type="text" placeholder="Imie Zwierzaka" id="imieZwierzaka" />
                <input type="text" placeholder="Rasa Zwierzaka" id="rasaZwierzaka" />
                <input type="button" value="Dodaj zwierzaka" onclick="dodajZwierzaka();" />
            </div>
        </div>
        <div class="row" style="margin-top: 40px;">
            <input type="submit" value="Dodaj cały model" />
        </div>
    </div>
}

<script type="text/javascript">
    function dodajZwierzaka() {
        var imiezwierza = $("#imieZwierzaka").val();
        var rasazwierza = $("#rasaZwierzaka").val();
        var json = '{"Rasa":"' + rasazwierza + '" ,"Imie":"'+ imiezwierza+'"}';
        $.ajax({
            url: "/Home/AddToSession",
            type: "POST",
            data: json,
            dataType: 'json',
            contentType: "application/json; charset=utf-8"
        });
    }
</script>

 
0

Nie, używanie Session do tego celu, to nie jest żadna dobra praktyka, wręcz przeciwnie.

Co jest właściwie celem?
a) wyświetlenie listy istniejących adresów w trybie tylko do odczytu oraz edytora dodawanie nowego adresu;
b) wyświetlenie listy istniejących adresów w polach umożliwiających ich edycję oraz edytora dodawania nowego adresu.

Jeżeli to pierwsze, to wystarczy tylko utworzyć form z polami na nowy adres, a po submicie robić post-redirect-get.

Jeżeli to drugie, to najprostsze podejście to dodanie do listy nowego pustego obiektu (nie null tylko obiektu adresu bez podanych wartości). Wtedy w pętli automatycznie zostaną wyrenderowane puste pola, a po submicie nowy wpis trafi na serwer. Potem wystarczy tylko przeładować stronę.

Jeśli chcesz bez przeładowania strony, to bez JS się nie obejdzie.

0

Już piszę o co chodzi w celu:

  1. Pobieram kontrahenta z kontrolera z listą adresów
  2. Wyświetlam dane kontrahenta oraz adresy przez Razor Syntax
  3. Kiedy naciskam submit i chce zapisać zmiany w kontrahencie, do kontrolera trafiają pola kontrahenta ale nie trafia lista adresów (Count = 0), nawet jeśli nie zmieniam w tych adresach nic.

Cel jest taki żeby one tam mogły trafić

EDIT:

Z tym sobie już poradziłem.

Natomiast mam pytanie co do Twojego posta

somekind napisał(a):

Nie, używanie Session do tego celu, to nie jest żadna dobra praktyka, wręcz przeciwnie.

Co jest właściwie celem?
a) wyświetlenie listy istniejących adresów w trybie tylko do odczytu oraz edytora dodawanie nowego adresu;
b) wyświetlenie listy istniejących adresów w polach umożliwiających ich edycję oraz edytora dodawania nowego adresu.

Jeżeli to pierwsze, to wystarczy tylko utworzyć form z polami na nowy adres, a po submicie robić post-redirect-get.

Jeżeli to drugie, to najprostsze podejście to dodanie do listy nowego pustego obiektu (nie null tylko obiektu adresu bez podanych wartości). Wtedy w pętli automatycznie zostaną wyrenderowane puste pola, a po submicie nowy wpis trafi na serwer. Potem wystarczy tylko przeładować stronę.

Jeśli chcesz bez przeładowania strony, to bez JS się nie obejdzie.

Mogę użyć JS tylko chciałbym móc dodać wiele elementów do listy, nie zapisując ich do bazy. Coś na wzór pomysłu z nullem, ale gdy próbuje dodać coś ręcznie co nie jest na liście nie binduje się to.

0 użytkowników online, w tym zalogowanych: 0, gości: 0