2012-10-30 12 views
5

Potrzebuję zbudować dynamiczny formularz z bazy danych. Mam następujące jednostki do definiowania pól formularza w locie:Dynamiczny formularz budynku z knockoutjs

public class FormField { 
     public int ID { get; set; } 
     public string Name { get; set; } 
     public string Type { get; set; } // Possible values are: 'Radio','Combo','Text'. A dropdown will be created for a Combo type of element, a radio set for Radio type of element and a text input for Text type of element. 
     public string Options { get; set; } // Only relevant in case of Radio/Combo type 
     public string Default { get; set; } // Default value in case of Type 'Text' and selected value in case of Type 'Radio/Combo' 
     public string Blankout { get; set; }// An expression to define when this field should be hidden 
    } 

    /* A sample JSON array (from the DB) to build the form would be: 
     [ 
     { Name:"Gender", Type:"radio", Options:["Male","Female","Unknown"], Default:"Male", Blankout:"Never" }, 
     { Name:"Age", Type:"text", Options:"None", Default:15, Blankout:"Never" }, 
     { Name:"Neighbourhood", Type:"Combo", Options:["Eastern","Western","Northern","Southern","Central"], Default:"Central", Blankout:"if (Age < 40 or Voted='Obama')" }, 
     { Name:"Voted", Type:"Combo", Options:["Obama","Romney","Harry Potter"], Default:"Harry Potter", Blankout:"if ((Gender='Female' and Age < 15) or Neighbourhood='Eastern'" } 
     ] 
    */ 

mogę zbudować dynamiczną formę z ewidencji „FormField” w dB, ale problem jest i trzeba śledzić zmiany w wartości dowolnego pola formularza , a kiedy nastąpi zmiana wartości, muszę wysłać wszystkie dane formularza do serwera (asynchronicznie), aby ocenić formułę "pustego miejsca" na serwerze. Jeśli to zrobię, zmienię śledzenie bez KnockoutJS, który nie reaguje i staje się bardzo skomplikowany. Przeszedłem kilka tutoriali KnockoutJS, ale nie mogłem dowiedzieć się, jak zorganizować mój ViewModel dla tego konkretnego problemu.

Każda pomoc zostanie doceniona.

Update 1

Próbowałem pisać ten formularz danych do sterownika za pomocą następującego kodu:

$.ajax({ 
      type: "POST", 
      url: "/MyController/GetBlankoutElements", 
      contentType: 'application/json', 
      dataType: 'json', 
      data: JSON.stringify(ko.toJSON(self)), 
      success: function(result) { 
       alert(result); 
       //self.HiddenElements(result.split(',')); 
      } 
    }); 

W moim kontroler Próbowałem następujący kod:

[HttpPost] 
    public ActionResult GetBlankoutElements(List<MyFieldViewModel> Fields) 
    { 
     return Json(Fields); // List, Fields is null here 
    } 

Ona jest tym, czym wygląda klasa MyFieldViewModel:

public class MyFieldViewModel 
    { 
     public string Title { get; set; } 
     public string Name { get; set; } 
     public string Type { get; set; } 
     public string Default { get; set; } 
     public string[] Options { get; set; } 
    } 

próbowałem wskazówki opisane w Post an Array of Objects via JSON to ASP.Net MVC3

Poniżej dane JSON, który wypisuje kiedy wykonać alert (ko.toJSON (samodzielne))

{"Fields": 
     [{"Title":"CCType","Name":"CCType","Type":"Radio","Default":"Enterprise","Options":["Enterprise","Express","CVP","PCCE"]},{"Title":"Industry","Name":"Industry","Type":"Combo","Default":"Banks","Options":["Banks","ServiceProvider","Outsourcer","Airlines","Utilities","Government","Retail"]},{"Title":"Customer Lab","Name":"CustomerLab","Type":"Combo","Default":"0","Options":["0","1"]},{"Title":"No of Agents","Name":"Agents","Type":"Text","Default":"if(c.CCType==\"CVP\") then 10 else 25","Options":[]},{"Title":"ExpLicType","Name":"ExpLicType","Type":"Radio","Default":"if(c.CCType==\"Express\") then \"Enhanced\" else \"None\"","Options":["None","Premium","Standard","Enhanced"]},{"Title":"Multimedia","Name":"Multimedia","Type":"Combo","Default":"WIM","Options":["None","EIM","WIM","EIM&WIM","BSMediaRouting","MCAL"]}], 
    "HiddenElements":[] 
    } 

Co potrzebne jest tylko nazwa pola i jego wybrana przez użytkownika wartość i jestem zdezorientowany, nawet jeśli otrzymam te dane JSM odwzorowane na moją klasę MyFieldViewModel, nadal w jaki sposób otrzymam wybrane WARTOŚCI?

Aktualizacja 2(JSON Mapowanie danych pracował)

Kiedy zmienił

data: JSON.stringify(ko.toJSON(self)) 

z danych: ko.toJSON (self)

Mapowanie pracował idealnie na moim kontrolera , jak widać na poniższym zrzucie ekranu: Debug screenshot of Mapped list object from post json data

Teraz pozostaje problem, cały formularz wysyłania formularzy polegał na aktualizacji serwera za pomocą danych wprowadzonych przez użytkownika w formularzu, tj. Wartości w odniesieniu do każdego elementu pola formularza. Jak wysłać bieżące wybrane/wpisane wartości pól formularza? Na przykład na powyższym zrzucie ekranu widzę wartość domyślną, ale nie aktualną wybraną wartość.

Odpowiedz

8

Do śledzenia zmian można użyć dirty flag z tego artykułu: http://www.knockmeout.net/2011/05/creating-smart-dirty-flag-in-knockoutjs.html.

utworzyć następujące modelu wyświetlania:

function FormField(data) { 
    var self = this; 

    self.Name = ko.observable(data.Name); 
    self.Type = ko.observable(data.Type); 
    self.Options = ko.observableArray(data.Type != 'text' ? data.Options : []); 
    self.Default = ko.observable(data.Default); 
} 

function ViewModel(data) { 
    var self = this; 

    self.Fields = ko.observableArray(ko.utils.arrayMap(data, function(item) { 
     return new FormField(item); 
    })); 

    self.dirtyFlag = new ko.dirtyFlag(this); 

    self.isDirty = ko.computed(function(){ 
     if (self.dirtyFlag.isDirty()) 
     { 
      alert("Value changed!"); 
      // Do async update. 
     } 
    }); 
} 

znaczników HTML: skrzypce

<div data-bind="foreach: Fields"> 
    <b data-bind="text: Name"></b> 
    <!--ko if: Type() == "combo"--> 
     <select data-bind="options: Options, value: Default"></select>     <!--/ko--> 
    <!--ko if: Type() == "radio"--> 
     <div data-bind="foreach: Options"> 
      <input type="radio" value="cherry" data-bind="value: $data, checked: $parent.Default" /> 
      <span data-bind="text: $data"></span> 
     </div> 
    <!--/ko-->  
    <!--ko if: Type() == "text"--> 
     <input type="text" data-bind="value: Default"></input>     
    <!--/ko--> 
    <br/>  
</div> 

Oto robocza: http://jsfiddle.net/vyshniakov/CWTTR/

EDIT:

Oto odpowiedzi na pytania w razie Rozumiałem je poprawnie:

Aby opublikować wszystkie pola na serwerze, można użyć funkcji ko.toJSON(self). Rozmowa ajax będzie wyglądać następująco:

$.ajax({ 
     type: "POST", 
     url: "controller/action", 
     contentType: 'application/json', 
     data: JSON.stringify(ko.toJSON(self)), 
     success: function(result) { 
      self.HiddenElements(result); 
     } 
    }); 

spojrzenie na aktualne skrzypcach, aby zobaczyć, jak ukryć niektóre pola w zależności od odpowiedzi z serwera: http://jsfiddle.net/vyshniakov/CWTTR/1/.

+0

Dziękuję bardzo za @ Artem za tak szybką odpowiedź. Odpowiada to budowie dynamicznej części formy. Muszę również ukryć niektóre pola w środowisku wykonawczym, aby to zrobić, będę publikować "Wszystkie dane formularza" na serwerze, gdy nie mogę statycznie wpisać nazwy elementów w atrybucie danych żądania AJAX. Po drugie, powiedzmy, że serwer zwraca listę JSON, zawierającą nazwy tych elementów, które muszą być ukryte. Zniknęłoby wszystkie takie elementy na formularzu (jednocześnie odkrywając jakikolwiek inny element, który wcześniej był ukryty). Mam nadzieję, że zrozumiałeś mój problem. Naprawdę doceniam twój wysiłek. –

+0

@Akeel - brzmi, jakbyś był blisko. Możesz spowodować, że 'Blankout' będzie obserwowalny, a następnie użyje wiązania' visible' lub 'if' względem każdego z nich lub stworzy obliczone, które reprezentuje niewidoczne pola (zwraca tablicę), a następnie' foreach' przez to. Możesz wykonać żądanie AJAX, gdy zabrudzona flaga odpali i kiedy twoja odpowiedź zwróci aktualizację 'Blankout' obserwowalną na każdym polu. Czy poprawnie rozumiem twój scenariusz? –

+0

@Akeel zobacz zaktualizowany post. –