2013-11-25 3 views
0

으로 전달 페이지에 네 개의 컨트롤이 있습니다. 성, 이름 및 생년월일이있는 간단한 양식과 일부 국가 이름이있는이 드롭 다운이 있습니다. 이러한 컨트롤을 변경하면 아래의 SavePersonDetails POST 매개 변수로 전달되는 viewModel의 변경 사항을 볼 수 있지만 해당 뷰 모델에서 LocationId가 업데이트 된 것을 결코 볼 수 없으며 그 이유를 모르겠습니다. 드롭 다운 목록에서 선택한 항목을보기 모델

, 나는 내 마크 업이 무엇인지 Index.cshtml입니다 : 내 사람과 드롭을로드하는 간단한 컨트롤러가

public class PersonViewModel 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public DateTime DateOfBirth { get; set; } 
    public string LocationId { get; set; } 
    public IEnumerable<SelectListItem> Locations { get; set; } 
} 

:

@model Mvc4withKnockoutJsWalkThrough.ViewModel.PersonViewModel 
@using System.Globalization 
@using Mvc4withKnockoutJsWalkThrough.Helper 

@section styles{ 
@Styles.Render("~/Content/themes/base/css") 
<link href="~/Content/Person.css" rel="stylesheet" /> 
} 

@section scripts{ 
@Scripts.Render("~/bundles/jqueryui") 
<script src="~/Scripts/knockout-2.1.0.js"></script> 
<script src="~/Scripts/knockout.mapping-latest.js"></script> 
<script src="~/Scripts/Application/Person.js"></script> 
<script type="text/javascript"> 
    Person.SaveUrl = '@Url.Action("SavePersonDetails", "Person")'; 
    Person.ViewModel = ko.mapping.fromJS(@Html.Raw(Json.Encode(Model))); 
    var userObject = '@Html.Raw(Json.Encode(Model))'; 
    var locationsArray = '@Html.Raw(Json.Encode(Model.Locations))'; 
    var vm = { 
     user : ko.observable(userObject), 
     availableLocations: ko.observableArray(locationsArray) 
    }; 
    ko.applyBindings(vm); 
</script> 
} 
<form> 
<p data-bind="with: user"> 
     Your country: 
     <select data-bind="options: $root.availableLocations, optionsText: 'Text', optionsValue: 'Value', value: LocationID, optionsCaption: 'Choose...'"> 
     </select> 
    </p> 
</form> 

이 내보기 모델입니다 3 개국이 포함 된 목록.

private PersonViewModel _viewModel; 

public ActionResult Index() 
{   
    var locations = new[] 
    { 
     new SelectListItem { Value = "US", Text = "United States" }, 
     new SelectListItem { Value = "CA", Text = "Canada" }, 
     new SelectListItem { Value = "MX", Text = "Mexico" }, 
    }; 

    _viewModel = new PersonViewModel 
    { 
     Id = 1, 
     FirstName = "Test", 
     LastName = "Person", 
     DateOfBirth = new DateTime(2000, 11, 12), 
     LocationId = "", // I want this value to get SET when the user changes their selection in the page 
     Locations = locations 
    }; 

    _viewModel.Locations = locations; 

    return View(_viewModel); 
} 

[HttpPost] 
public JsonResult SavePersonDetails(PersonViewModel viewModel) 
{ 
    int id = -1; 

    SqlConnection myConnection = new SqlConnection("server=myMachine;Trusted_Connection=yes;database=test;connection timeout=30"); 

    try 
    { 
      // omitted 
    } 
    catch (Exception e) 
    { 
     Console.WriteLine(e.ToString()); 
    } 
    finally 
    { 
     myConnection.Close(); 
    } 
    return Json(id, "json"); 
} 

마지막으로, 여기 당신이 볼 수 있듯이, 나는 페이지의 데이터를 가지고 있지만 그들 중 누구도 선택으로 보여주지 내 Person.js 파일, 내가 사용 녹아웃

var Person = { 

PrepareKo: function() { 
    ko.bindingHandlers.date = { 
     init: function (element, valueAccessor, allBindingsAccessor, viewModel) { 
      element.onchange = function() { 
       var observable = valueAccessor(); 
       observable(new Date(element.value)); 
      } 
     }, 
     update: function (element, valueAccessor, allBindingsAccessor, viewModel) { 
      var observable = valueAccessor(); 
      var valueUnwrapped = ko.utils.unwrapObservable(observable); 
      if ((typeof valueUnwrapped == 'string' || valueUnwrapped instanceof String) && valueUnwrapped.indexOf('/Date') === 0) { 
       var parsedDate = Person.ParseJsonDate(valueUnwrapped); 
       element.value = parsedDate.getMonth() + 1 + "/" + parsedDate.getDate() + "/" + parsedDate.getFullYear(); 
       observable(parsedDate); 
      } 
     } 
    }; 
}, 

ParseJsonDate: function (jsonDate) { 
    return new Date(parseInt(jsonDate.substr(6))); 
}, 

BindUIwithViewModel: function (viewModel) { 
    ko.applyBindings(viewModel); 
}, 

EvaluateJqueryUI: function() { 
    $('.dateInput').datepicker(); 
}, 

RegisterUIEventHandlers: function() { 

    $('#Save').click(function (e) { 

     // Check whether the form is valid. Note: Remove this check, if you are not using HTML5 
     if (document.forms[0].checkValidity()) { 

      e.preventDefault(); 

      $.ajax({ 
       type: "POST", 
       url: Person.SaveUrl, 
       data: ko.toJSON(Person.ViewModel), 
       contentType: 'application/json', 
       async: true, 
       beforeSend: function() { 
        // Display loading image 
       }, 
       success: function (result) { 
        // Handle the response here. 
        if (result > 0) { 
         alert("Saved"); 
        } else { 
         alert("There was an issue"); 
        } 

       }, 
       complete: function() { 
        // Hide loading image. 
       }, 
       error: function (jqXHR, textStatus, errorThrown) { 
        // Handle error. 
       } 
      }); 
      } 
     }); 
    }, 
}; 

$(document).ready(function() { 
    Person.PrepareKo(); 
    Person.BindUIwithViewModel(Person.ViewModel); 
    Person.EvaluateJqueryUI(); 
    Person.RegisterUIEventHandlers(); 
}); 

입니다

locations

답변

1

귀하의 솔루션은 지나치게 복잡하며 귀하의 데이터와 함께 이상하게 이어지고 있습니다. 타이타닉 패치를 시도하는 대신, 가장 좋은 방법은 처음부터 다시 시작하는 것입니다.

페이지의 모델에 필요한 모든 정보가 포함되어 있습니다. 사용자 데이터와 위치를 함께 사용하기 위해 두 개의 완전히 다른보기 모델을 만들 필요가 없습니다. 매핑 플러그인을 사용하면 기본보기 모델의 다양한 객체에 대해 서로 다른 "보기 모델"을 지정할 수 있으며 모든 것을 설정하기 위해 따라야하는 더 단순한 패턴이 있습니다. 여기에 내가 무엇을 할 것이라고입니다 :

// The following goes in external JS file 

var PersonEditor = function() { 
    var _init = function (person) { 
     var viewModel = PersonEditor.PersonViewModel(person); 
     ko.applyBindings(viewModel); 
     _wireEvents(viewModel); 
    } 

    var _wireEvents = function (viewModel) { 
     // event handlers here 
    } 

    return { 
     Init: _init 
    } 
}(); 

PersonEditor.PersonViewModel = function (person) { 
    var mapping = { 
     'Locations': { 
      create: function (options) { 
       return new PersonEditor.LocationViewModel(options.data) 
      } 
     } 
    } 
    var model = ko.mapping.fromJS(person, mapping); 

    // additional person logic and observables 

    return model; 
} 

PersonEditor.LocationViewModel = function (location) { 
    var model = ko.mapping.fromJS(location); 

    // additional location logic and observables 

    return model; 
} 

// the following is all you put on the page 

<script src="/path/to/person-editor.js"></script> 
<script> 
    $(document).ready(function() { 
     var person = @Html.Raw(@Json.Encode(Model)) 
     PersonEditor.Init(person); 
    }); 
</script> 

은 모든 사용자가 위치 배열에 선택 목록을 결합해야하는 것은 :

<p> 
    Your country: 
    <select data-bind="options: Locations, optionsText: 'Text', optionsValue: 'Value', value: LocationId, optionsCaption: 'Choose...'"> 
    </select> 
</p> 
+0

많은 의견을 보내 주셔서 감사합니다. 나는 그것이 잘 작동한다고 확신하지만, 약간의 재 작업이 필요하며, 명확하지 않은 부분이있다. MVC 및 jQuery에 대한 나의 이해가 제한되어 있으므로 드롭 다운 목록에서 값을 가져 와서 ViewModel을 업데이트하기를 원했습니다. 그것에 대해 제안 해 주시겠습니까? 나는 이것을 시도했다 : BindUIwithViewModel : function (viewModel) {ko.applyBindings (viewModel.LocationId, document.getElementById ("location_list"). selectedIndex.text); ko.applyBindings (viewModel);} –

+0

저장 내용이 완전히 동일합니다. 뷰 모델을 직렬화 할 때 Select의 값을'LocationId'에 바인딩하면 적절히 설정되어 사후 조치로 다시 전달됩니다. –

+0

나는 일하러 가고 있지 않습니다. 나는 문서가 준비되었을 때 BindUIwithViewModel이 실행되어 LocationId에 값을 할당 할 수있는 기회를 얻지 못한다는 것을 알았습니다. 나는 또한 내 아약스 POST의 beforeSend에 값을 할당하려고 시도했지만 실제로 할당 된 값은 없다. 나는 이것으로 정말 길을 잃었고 간단하다고 확신하지만 나는 막혔다. –

0

업데이트 된 질문을 바탕으로,이 작업을 수행.

1. 실제로 locationsArray이 필요하지 않습니다. 그것의 이미 user.Locations (어리석은 me)
에 2.On Index.cshtml, 페이지는 이와같이 자바 스크립트를 바꾼다.

var userObject = @Html.Raw(Json.Encode(Model)); // no need for the quotes here 
jQuery(document).ready(function ($) { 
    Person.PrepareKo(); 
    Person.EvaluateJqueryUI(); 
    Person.RegisterUIEventHandlers(); 
    Person.SaveUrl = "@Url.Action("SavePersonDetails", "Knockout")"; 
    Person.ViewModel = { 
     user : ko.observable(userObject) 
    }; 
    Person.BindUIwithViewModel(Person.ViewModel); 
}); 

3.On 당신의 Person.js 페이지, RegisterUIEventHandlers #Save 버튼 클릭 이벤트 내부에서이 작업을 수행.

$('#Save').click(function (e) { 
    var updatedUser = Person.ViewModel.user(); 
    updatedUser.Locations.length = 0; // not mandatory, but we don't need to send extra payload back to server. 
    // Check whether the form is valid. Note: Remove this check, if you are not using HTML5 
    if (document.forms[0].checkValidity()) { 
     e.preventDefault(); 
     $.ajax({ 
      type: "POST", 
      url: Person.SaveUrl, 
      data: ko.toJSON(updatedUser), // Data Transfer Object 
      contentType: 'application/json', 
      beforeSend: function() { 
       // Display loading image 
      } 
     }).done(function(result) { 
      // Handle the response here. 
      if (result > 0) { 
       alert("Saved"); 
      } else { 
       alert("There was an issue"); 
      } 
     }).fail(function(jqXHR, textStatus, errorThrown) { 
      // Handle error. 
     }).always(function() { 
      // Hide loading image. 
     }); 
    } 
}); 

5.Finally 우리 마크 무관 한 측면에서 주

<p data-bind="with: user"> 
    Your country: 
    <select data-bind="options: Locations, 
       optionsText: 'Text', 
       optionsValue: 'Value', 
       value: LocationId, 
       optionsCaption: 'Choose...'"> 
    </select> 
</p> 

,

jqXHR.success() jqXHR.error() 및 jqXHR.complete() 콜백은 이며 jQuery 1.8에서는 더 이상 사용되지 않습니다. 최종적으로 코드 을 제거하려면 jqXHR.done(), jqXHR.fail() 및 jqXHR.always()를 대신 사용하십시오.

관련 문제