[ASP.NET MVC]Veld alleen verplicht als sectie is uitgeklapt

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 21:16

Haan

dotnetter

Topicstarter
Ik loop weer tegen een issue aan in een ASP.NET MVC3 project ;)

Ik heb een formulier waarop mensen o.a. hun vooropleiding in kunnen vullen. Hiervoor heb ik een model met een paar verplichte velden en een partial view waarop de velden staan.

Nu is de wens dat mensen minimaal 1 en maximaal drie vooropleidingen in kunnen vullen. In ASP.NET webforms zou ik dat oplossen dmv een knopje of link waarmee je een sectie op de pagina uit kan klappen om een volgende vooropleiding in te vullen. In de code-behind zou ik dan de validators voor die sectie enablen.

Maar voor MVC3 ben ik er nog niet helemaal uit. Moet ik die tweede en derde sectie al verborgen in de view zetten, met een 'niet verplicht' model zodat je het formulier wel kan submitten als je maar één vooropleiding in wil vullen? Maar hoe krijg je op dat moment dan de validatie weer 'aan'? Of kan je ook 'on-the-fly' stukjes partial view laten renderen? Ik denk dat zoiets wel mogelijk moet zijn, maar heb er nog geen concreet voorbeeld van kunnen vinden.

Suggesties zijn welkom :)

Kater? Eerst water, de rest komt later


Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 21:16

Haan

dotnetter

Topicstarter
Ik ben volgens mij al per ongeluk tegen een oplossing aangelopen \o/

Hier is een pagina op SO waar de oplossing voor het grootste deel in staat. Maar het staat er wat versnipperd en niet helemaal compleet, dus nog even hier op een rijtje:
- gebruik @Ajax.ActionLink:
C#:
1
@Ajax.ActionLink("Nog een vooropleiding", "LoadPrestudySection", new AjaxOptions {InsertionMode = InsertionMode.Replace, UpdateTargetId = "prestudy2", HttpMethod = "get" })

Hierbij verwijs je dus naar een Controller actie, en vertel je dat de inhoud van element met ID 'prestudy2' vervangen dient te worden.
- Controller actie die een PartialView teruggeeft:
C#:
1
2
3
4
5
public PartialViewResult LoadPrestudySection()
{
    // indien nodig kan je ook een model meegeven aan de partial view
    return PartialView("_prestudy");
}


Belangrijk (dit ontbreekt op de SO pagina):
In de view waarin de ActionLink staat, moet een verwijzing staan naar jquery.unobtrusive.ajax, anders opent de view in een nieuwe pagina in plaats van netjes op de goede plek.
MSDN: Walkthrough: Adding ASP.NET AJAX Scripting to an MVC Project

Nu alleen nog verzinnen hoe ik die vooropleidingen in het bovenliggende model krijg..

[ Voor 8% gewijzigd door Haan op 04-08-2011 11:55 ]

Kater? Eerst water, de rest komt later


Acties:
  • 0 Henk 'm!

  • D-Raven
  • Registratie: November 2001
  • Laatst online: 10:35
Nooit echt gebruikt die Ajax extensies in het MVC framework. Op een of andere manier wil ik altijd dingen doen die niet ondersteund worden :P
Zoals het meesturen van het antiforgerytoken bij een async get request en dat soort dingen. Plus ik wil gewoon UrlHelper extensies kunnen gebruiken. Maw
C#:
1
 Ajax.ActionLink("text hier", Url.MijnUrl(), new { de rest });


Wat bedoel je precies met: vooropleidingen in het bovenliggende model krijgen.
Je kunt toch gewoon een lijst van vooropleidingen in je viewmodel stoppen?

Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 21:16

Haan

dotnetter

Topicstarter
Ik heb dus een model 'Subscription', daar had ik eerst een property 'PreStudy' in zitten voor de vooropleiding, dat werkte prima. Maar nu moet dat dus een IENumerable van vooropleidingen worden.
Daarbij heb ik nu het volgende probleem:
1. partial view voor vooropleiding gaf ik het subscription model mee ipv een vooropleiding, omdat ik nog niet had uitgevogeld hoe je anders de vooropleiding bij de subscription kon krijgen. Dat bedoel ik dus met 'vooropleidingen in het bovenliggende model krijgen'.
Ik ben nu naar deze pagina aan het kijken of het daarmee misschien werkt.

Kater? Eerst water, de rest komt later


Acties:
  • 0 Henk 'm!

  • D-Raven
  • Registratie: November 2001
  • Laatst online: 10:35
Als het er maximaal 3 mogen zijn zou ik het heel simpel houden:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SubscriptionViewModel {

      //of meteen al een SelectList
     public IEnumerable<StudieViewModel> Studies
     //int is studie id
     public int Studie1 {get;set;}
     
     public int Studie2 {get;set;}

     public int Studie3 {get;set;}

    public SelectList GetStudieList() {
        return Studies.ToSelectList("ID", "Beschrijving"); //oid
    }
}


je view (spark syntax)
C#:
1
2
3
4
5
    
 !{Html.DropdownList("Studie1", Model.GetStudieList())}
 //en dan de rest via partial views of whatnot ophalen, op basis van whatever logica je wilt
 !{Html.DropdownList("Studie2", Model.GetStudieList())}
 !{Html.DropdownList("Studie3", Model.GetStudieList())}

Acties:
  • 0 Henk 'm!

  • Grijze Vos
  • Registratie: December 2002
  • Laatst online: 28-02 22:17
D-Raven schreef op donderdag 04 augustus 2011 @ 12:31:
Op een of andere manier wil ik altijd dingen doen die niet ondersteund worden :P
Bij de Unobtrusive variant kun je toch relatief makkelijk de javascript sources aanpassen die in je project gebakken zitten en zo functionaliteit toevoegen.

Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info


Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 21:16

Haan

dotnetter

Topicstarter
@Deathraven, het gaat niet om een dropdownlist met vooropleidingen, maar echt om een partial view waar je zelf een aantal velden in kan vullen (naam/plaats opleiding, begin/eind jaar e.d.)

Ik ben even aan het testen geslagen in een testprojectje, dat werkt wat handiger. Voor eenvoud werk ik nu eerst met twee classes:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
public class Parent
    {
        [Required]
        public string ParentField { get; set; }
        public IEnumerable<Child> Children { get; set; } 
    }

    public class Child
    {
        [Required]
        public string ChildField { get; set; }
    }


Ik heb een view voor de Parent:
HTML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Parent</legend>
        <div class="editor-label">
            @Html.LabelFor(model => model.ParentField)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ParentField)
            @Html.ValidationMessageFor(model => model.ParentField)
        </div>
    </fieldset>

@Ajax.ActionLink("Laad child", "LoadChild", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "child", HttpMethod = "get" })

<div id="child">
</div>

<p>
    <input type="submit" value="Create" />
</p>
}


De partial view met child model:
HTML:
1
2
3
4
5
6
7
8
9
10
11
12
13
@model MvcApplication1.Models.Child

<fieldset>
        <legend>Child</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.ChildField)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ChildField)
            @Html.ValidationMessageFor(model => model.ChildField)
        </div>
    </fieldset>


En een controller:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 public class TestController : Controller
    {
        public ActionResult Index()
        {
            Parent model = new Parent();
            model.Children = new List<Child>();
            return View(model);
        }

        [HttpPost]
        public ActionResult Index(Parent model)
        {
            if (!ModelState.IsValid)
            {
                return View();
            }

            return View();
        }

        public ActionResult LoadChild()
        {
            return PartialView("_child");
        }
    }


Meer uitgekleed dan dit kan niet volgens mij :P
Maar hierbij is het probleem nu al dat ten eerste de validatie voor het Child field niet afgaat, en ten tweede dat de Child überhaupt niet gepost wordt..

[ Voor 86% gewijzigd door Haan op 04-08-2011 13:45 ]

Kater? Eerst water, de rest komt later


Acties:
  • 0 Henk 'm!

  • mindcrash
  • Registratie: April 2002
  • Laatst online: 22-11-2019

mindcrash

Rebellious Monkey

Ik ben bang dat je hiervoor echt een custom model binder nodig gaat hebben, met name omdat MVC volgens mij lijstjes van gegevensmodellen met een door de gebruiker zelf op te geven lengte OOTB niet snapt (en al helemaal niet als je bepaalde eisen hebt m.b.t. validatie)

[ Voor 60% gewijzigd door mindcrash op 04-08-2011 13:43 ]

"The people who are crazy enough to think they could change the world, are the ones who do." -- Steve Jobs (1955-2011) , Aaron Swartz (1986-2013)


Acties:
  • 0 Henk 'm!

  • D-Raven
  • Registratie: November 2001
  • Laatst online: 10:35
Haan schreef op donderdag 04 augustus 2011 @ 13:30:
@Deathraven, het gaat niet om een dropdownlist met vooropleidingen, maar echt om een partial view waar je zelf een aantal velden in kan vullen (naam/plaats opleiding, begin/eind jaar e.d.)
Ah je kiest dus geen opleiding, maar je vult m zelf in.
Dit moet nog wel kunnen met de standaard modelbinder. Out of the box niet nee, maar een beetje "elbow grease" kan het wel. ;)

Alleen dan moet je zorgen dat de "name" propertie van je invoer velden goed staan.
Om even een voorbeeld te geven zie: dit

En dan met name dit stukje:

code:
1
2
3
   1:  <%= Html.TextBox(string.Format("Products[{0}].ID", i), Model.Products[i].Id) %>
   2:  <!-- this will be rendered as -->
   3:  <input id="Products_0__ID" name="Products[0].ID" type="text" value="1" />


Ik gebruik voor deze dingen een Html.NameOf extension method ipv string format. Ik heb m hier alleen niet zo bij de hand anders zou ik m even posten, maar ik denk dat je deze op Google ook wel kan vinden. (net even gekeken, niet dus)

Maar in ieder geval zul je dus bij het teruggeven van je partial view de juiste names moeten genereren. Je zult dus iets van een item id moeten meegeven zodat je de juiste name kan genereren.
Maar als je dit voor elkaar krijg kun je gewoon binden naar een lijst van objecten.

Persoonlijk zou ik de controller action zelf aanroepen met een jquery get, en aan deze zelf een row id parameter meegeven welke je in je view gebruikt om de juiste namen te genereren.

Iets van:

JavaScript:
1
2
3
4
5
6
7
8
$.get(
   "url naar controller action",
   RowId : 0, //of 1 of 2 oid
   function(data) {
      $("element waar ik mijn partial in wil toevoegen").append(data); //of niet hoe je t wilt doen
   }.
   "html" //of json
);

Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 21:16

Haan

dotnetter

Topicstarter
Nog geen sluitende oplossing gevonden :(

Mijn idee is nu om het wat simpeler aan te pakken. Om even bij het simpele voorbeeld te blijven: ik heb de models nu als volgt:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Parent
    {
        [Required]
        public string ParentField { get; set; }

        public Child Child1 { get; set; }
        public OptionalChild Child2 { get; set; }
    }

    public class Child
    {
        [Required]
        public virtual string ChildField { get; set; }
    }

    public class OptionalChild : Child
    {
        public override string ChildField { get; set; }
    }


in de view staat nu dit:
HTML:
1
2
3
4
5
6
<div id="child1">
        @Html.EditorFor(model => model.Child1)
    </div>
    <div id="child2">
        @Html.EditorFor(model => model.Child2)
    </div>

De partial view heb ik veranderd naar een editor template. En dan gewoon maar eerst child1 tonen, met knopje om de overige childs uit te klappen (die dus met display:none al op het formulier staan)

Dat leek goed te gaan werken, alleen blijft het veld bij de OptionalChild als verplicht aangemerkt worden |:(

Kater? Eerst water, de rest komt later


Acties:
  • 0 Henk 'm!

  • D-Raven
  • Registratie: November 2001
  • Laatst online: 10:35
Je kunt ook jquery templates gebruiken om de extra child erbij te renderen. Maarja wederom, je moet ervoor willen werken :+
Pagina: 1