2016-08-30 2 views
5

Ich versuche, ein AutoComplete-Textfeld zu erstellen, während Sie eine verwenden. Das Problem, das ich gegenüberstelle, ist, dass mit der Html.BeginCollectionItem() Extension-Lösung (https://www.nuget.org/packages/BeginCollectionItem/), die IDs der EditorFor() und TextBoxFor() Methoden dynamisch gesetzt werden und das bricht mein Javascript. Darüber hinaus weiß ich nicht genau, ob das überhaupt möglich ist (und wenn ja, wie. Im Folgenden finden Sie, wie weit ich gekommen bin).MVC AutoComplete EditorFor während der Verwendung von Html.BeginCollectionItem

in der Hauptansicht I eine Schleife eine Teilansicht für jedes Element in einer Sammlung

for (int i = 0; i < Model.VoedingCollection.Count; i++) 
{ 
    @Html.EditorFor(x => x.VoedingCollection[i], "CreateVoedingTemplate") 
} 

die Teilansicht CreateVoedingTemplate.cshtml verwendet die Html.BeginCollectionItem() Methode

@using (Html.BeginCollectionItem("VoedingCollection")) 
{ 
    string uniqueId = ViewData.TemplateInfo.HtmlFieldPrefix.Replace('[', '_').Replace(']', '_').ToString(); 
    string searchId = "Search_"; 
    string standaardVoedingId = "StandaardVoeding_"; 
    foreach (KeyValuePair<string, object> item in ViewData) 
    { 
     if (item.Key == "Count") 
     { 
      searchId = searchId + item.Value.ToString(); 
      standaardVoedingId = standaardVoedingId + item.Value.ToString(); 
     } 
    } 

    <div class="form-horizontal"> 
     <div class="form-group" [email protected]> 
      @Html.LabelFor(model => model.fk_standaardVoedingId, "Voeding naam", htmlAttributes: new { @class = "control-label col-md-2" }) 
       <div class="col-md-10"> 
        @Html.HiddenFor(model => model.fk_standaardVoedingId) 
        <input type="text" id='@searchId' placeholder="Search for a product"/> 
       </div> 
     </div> 
    </div> 

    <script type="text/javascript"> 
     var id = '@uniqueId' + '_fk_standaardVoedingId'.toString(); 
     var search = '@searchId'.toString(); 

     var url = '@Url.RouteUrl("DefaultApi", new { httproute = "", controller = "AgendaApi" })'; 

     $(document.getElementById(search)).autocomplete({ 
      source: function (request, response) { 
       $.ajax({ 
        url: url, 
        data: { query: request.term }, 
        dataType: 'json', 
        type: 'GET', 
        success: function (data) { 
         response($.map(data, function (item) { 
          return { 
           label: item.standaardVoedingNaam, 
           value: item.standaardVoedingId 
          } 
         })); 
        } 
       }) 
      }, 
      select: function (event, ui) { 
       $(document.getElementById(search)).val(ui.item.label); 
       //$('#id').val(ui.item.value); 
       document.getElementById(id).value = ui.item.value; 
       return false; 
      }, 
      minLength: 1 
     }); 
    </script> 
} 

<link href="~/Content/SearchBox/jquery-ui.css" rel="stylesheet" /> 
<script src="~/Scripts/SearchBox/jquery-1.9.1.js"></script> 
<script src="~/Scripts/SearchBox/jquery-ui.js"></script> 

Im Skript

oben zu erzeugen, Ich versuche, eine Funktion zu machen, wo der Benutzer den Namen eines standaardVoeding Elements eingeben und dann Ergebnisse erhalten kann, wo, nachdem der Benutzer ein standaardVoeding Element auswählt, die standaardVoedingId Eigenschaft erhält einstellen. Dann, nachdem das gesamte Formular einreichen, der Regler die standaardVoedingId empfängt (mit allen anderen Informationen auch)

Also ich denke, Javascript irgendwie nicht den Razor Ansicht @ Code verarbeiten kann, und daneben, tut Html.BeginCollectionItem etwas faul, weil Sie kann den Wert seiner Textfelder über den Code zur Laufzeit nicht setzen. Daneben habe ich versucht, alert(document.getElementById(*html.begincollectionitemId*)) zu tun, und es findet die Felder gut. Aber anscheinend funktionieren alle anderen Methoden nicht?

Gibt es vielleicht eine bessere Lösung, um dies zum Laufen zu bringen?

+0

Entschuldigung! Was genau ist das Problem, vor dem Sie stehen? – Shyju

+0

Verwenden Sie einfach einen Klassennamen, um das Plugin anzuhängen (keine ID-Attribute) –

+0

Das Problem, mit dem ich konfrontiert bin, ist, dass mit dem hier geschriebenen Code die Aktion nicht an den Controller gesendet wird. Wie kann ich die Daten binden, die ich zurückbekomme, wenn ich den Wert eines Html.BeginCollectionItem-Feldes durch Javascript scheinbar nicht einstellen kann? Also, im Grunde möchte ich ein Autocomplete-Formular, das einen Wert zurückgibt und diesen Wert an eine Eigenschaft eines Modells bindet. – DaGrooveNL

Antwort

1

Die BeginCollectionItem() Methode verändert die id und name Attribute des HTML durch den eingebauten Helfer erzeugt, in Ihrem Fall die versteckten Eingang, statt

<input ... name="fk_standaardVoedingId" .... /> 

wird es generieren

<input ... name="VoedingCollection[xxxx].fk_standaardVoedingId" .... /> 

wobei xxxx ein Guid ist.

Während es möglich sein würde, JavaScript zu verwenden, um den Guid Wert aus der Textbox zu extrahieren (das unter der Annahme richtig @Html.TextBoxFor() usind erzeugt wurde) und die ID des zugehörigen hidden Eingangs baut als Selektor zu verwenden, ist es viel leichter zu bedienen Klassennamen und relative Selektoren.

Sie müssen auch Ihre Skripte und CSS aus dem Teil entfernen und das in der Hauptansicht (oder deren Layout). Abgesehen von den Inline-Skripten duplizieren Sie sie für jedes Objekt in Ihrer Sammlung.

Ihre Teil-Bedürfnisse

@using (Html.BeginCollectionItem("VoedingCollection")) 
{ 
    <div class="form-horizontal"> 
     <div class="form-group"> 
      @Html.LabelFor(model => model.fk_standaardVoedingId, "Voeding naam", htmlAttributes: new { @class = "control-label col-md-2" }) 
      <div class="col-md-10 item"> // add class name 
       @Html.HiddenFor(model => model.fk_standaardVoedingId) 
       <input type="text" class="search" placeholder="Search for a product"/> 
      </div> 
     </div> 
    </div> 
} 

Hinweis der Klassenname für das Textfeld und seinen Behälter sein, die auch den verborgenen Eingang enthält.Dann in der Hauptansicht, wird das Skript

<script type="text/javascript"> 
    var url = '@Url.RouteUrl("DefaultApi", new { httproute = "", controller = "AgendaApi" })'; 
    // Attach the script to all textboxes 
    $('.search').autocomplete({ 
     source: function (request, response) { 
      $.ajax({ 
       url: url, 
       data: { query: request.term }, 
       dataType: 'json', 
       type: 'GET', 
       success: function (data) { 
        response($.map(data, function (item) { 
         return { 
          label: item.standaardVoedingNaam, 
          value: item.standaardVoedingNaam, // this needs to be the name 
          id: item.standaardVoedingId // add property for the id 
         } 
        })); 
       } 
      }) 
     }, 
     select: function (event, ui) { 
      // Get the associated hidden input 
      var input = $(this).closest('.item').find('input[type="hidden"]'); 
      // Set the value of the id property 
      input.val(ui.item.id); 
     }, 
     minLength: 1 
    }); 
</script> 

Basierend auf Ihren Kommentaren, die Sie nicht dynamisch hinzugefügt oder Elemente in der Ansicht zu entfernen, dann gibt es keinen Punkt in dem zusätzlichen Aufwand oder mit den BeginCollectionItem() Methode. Ändern Sie den Namen Ihres Partials in standaardvoeding.cshtml (vorausgesetzt, dass der Name der Klasse ist) und verschieben Sie es in den Ordner /Views/Shared/EditorTemplates.

dann in der Hauptansicht, ersetzen Sie Ihre for Schleife mit

@Html.EditorFor(m => m.VoedingCollection) 

, die dem richtigen HTML-Code für jedes Element in der Sammlung generieren. Schließlich entfernen Sie die BeginCollectionItem()-Methode aus der Vorlage, so dass es nur

<div class="form-horizontal"> 
    <div class="form-group"> 
     @Html.LabelFor(m => m.fk_standaardVoedingId, "Voeding naam", htmlAttributes: new { @class = "control-label col-md-2" }) 
     <div class="col-md-10 item"> // add class name 
      @Html.HiddenFor(m => m.fk_standaardVoedingId) 
      <input type="text" class="search" placeholder="Search for a product"/> 
     </div> 
    </div> 
</div> 
+0

Ihr JavaScript-Code enthält einen Fehler, es setzt die ID des Elements der Benutzer, der im Suchfeld anstelle von @ Html.HiddenFor (m => m.fk_standaardVoedingId) ausgewählt wurde – DaGrooveNL

+0

Was? 'var input = $ (this) .closes ('. item'). find ('input [type =" hidden "]);' erhält die versteckte Eingabe und 'input.val (ui.value);' setze den Wert ! Und das ist Ihr Code (der 'return {label: item.standaardVoedingNaam, value: item.standaardVoedingId}'), der das tut.Ich habe es einfach kopiert, weil ich angenommen habe, dass du das wolltest. –

+0

Sie haben auch einen Fehler im JavaScript-Code, Sie haben eine 'nahe Eingabe falsch eingegeben. Es funktioniert nicht. Ich habe es versucht, es setzt den Wert nicht. Meine Frage war, wie man das versteckte Feld mit der ID, die der Benutzer abruft, eingibt, indem er etwas eintippt und dann ein Element auswählt, und danach wird das versteckte Feld gesetzt. Das normale Suchfeld sollte auch auf den Wert (nicht die ID) eingestellt sein, den der Benutzer ausgewählt hat. – DaGrooveNL

Verwandte Themen