How to use knockout.js with ASP.NET MVC ViewModels?

前端 未结 3 608
暖寄归人
暖寄归人 2020-11-28 00:31

Bounty

It\'s been awhile and I still have a couple outstanding questions. I hope by adding a bounty maybe these questions will get answered.

3条回答
  •  孤独总比滥情好
    2020-11-28 01:00

    I think I have summarized all your questions, if I missed something please let me know (If you could summarize up all your questions in one place would be nice =))

    Note. Compatibility with the ko.editable plug-in added

    Download the full code

    How do you use html helpers with knockout.js

    This is easy:

    @Html.TextBoxFor(model => model.CourseId, new { data_bind = "value: CourseId" })
    

    Where:

    • value: CourseId indicates that you are binding the value property of the input control with the CourseId property from your model and your script model

    The result is:

    
    

    Why was document ready needed to make it work(see first edit for more information)

    I do not understand yet why you need to use the ready event to serialize the model, but it seems that it is simply required (Not to worry about it though)

    How do I do something like this if I am using the knockout mapping with my view models? As I do not have a function due to the mapping.

    If I understand correctly you need to append a new method to the KO model, well that's easy merging models

    For more info, in the section -Mapping from different sources-

    function viewModel() {
        this.addStudent = function () {
            alert("de");
        };
    };
    
    $(function () {
        var jsonModel = '@Html.Raw(JsonConvert.SerializeObject(this.Model))';
        var mvcModel = ko.mapping.fromJSON(jsonModel);
    
        var myViewModel = new viewModel();
        var g = ko.mapping.fromJS(myViewModel, mvcModel);
    
        ko.applyBindings(g);
    });
    

    About the warning you were receiveing

    Warning 1 Conditional compilation is turned off -> @Html.Raw

    You need to use quotes

    Compatibility with the ko.editable plug-in

    I thought it was going to be more complex, but it turns out that the integration is really easy, in order to make your model editable just add the following line: (remember that in this case I am using a mixed model, from server and adding extension in client and the editable simply works... it's great):

        ko.editable(g);
        ko.applyBindings(g);
    

    From here you just need to play with your bindings using the extensions added by the plug-in, for example, I have a button to start editing my fields like this and in this button I start the edit process:

        this.editMode = function () {
            this.isInEditMode(!this.isInEditMode());
            this.beginEdit();
        };
    

    Then I have commit and cancel buttons with the following code:

        this.executeCommit = function () {
            this.commit();
            this.isInEditMode(false);
        };
        this.executeRollback = function () {
            if (this.hasChanges()) {
                if (confirm("Are you sure you want to discard the changes?")) {
                    this.rollback();
                    this.isInEditMode(false);
                }
            }
            else {
                this.rollback();
                this.isInEditMode(false);
            }
        };
    

    And finally, I have one field to indicate whether the fields are in edit mode or not, this is just to bind the enable property.

    this.isInEditMode = ko.observable(false);
    

    About your array question

    I might have some foreach loops or something to get the data out of the collection of Student View Models.

    Then when I would submit the form I would use jquery and serialize array and send it to a controller action method that would bind it back to the viewmodel.

    You can do the same with KO, in the following example, I will create the following output:

    enter image description here

    Basically here, you have two lists, created using Helpers and binded with KO, they have a dblClick event binded that when fired, remove the selected item from the current list and add it to the other list, when you post to the Controller, the content of each list is sent as JSON data and re-attached to the server model

    Nuggets:

    • Newtonsoft
    • jQuery
    • knockoutjs
    • Knockout.Mapping

    External scripts.

    Controller code

        [HttpGet]
        public ActionResult Index()
        {
            var m = new CourseVM { CourseId = 12, CourseName = ".Net" };
    
            m.StudentViewModels.Add(new StudentVm { ID = 545, Name = "Name from server", Lastname = "last name from server" });
    
            return View(m);
        }
    
        [HttpPost]
        public ActionResult Index(CourseVM model)
        {
            if (!string.IsNullOrWhiteSpace(model.StudentsSerialized))
            {
                model.StudentViewModels = JsonConvert.DeserializeObject>(model.StudentsSerialized);
                model.StudentsSerialized = string.Empty;
            }
    
            if (!string.IsNullOrWhiteSpace(model.SelectedStudentsSerialized))
            {
                model.SelectedStudents = JsonConvert.DeserializeObject>(model.SelectedStudentsSerialized);
                model.SelectedStudentsSerialized = string.Empty;
            }
    
            return View(model);
        }
    

    Model

    public class CourseVM
    {
        public CourseVM()
        {
            this.StudentViewModels = new List();
            this.SelectedStudents = new List();
        }
    
        public int CourseId { get; set; }
    
        [Required(ErrorMessage = "Course name is required")]
        [StringLength(100, ErrorMessage = "Course name cannot be this long.")]
        public string CourseName { get; set; }
    
        public List StudentViewModels { get; set; }
        public List SelectedStudents { get; set; }
    
        public string StudentsSerialized { get; set; }
        public string SelectedStudentsSerialized { get; set; }
    }
    
    public class StudentVm
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Lastname { get; set; }
    }
    

    CSHTML page

    @using (Html.BeginForm())
    {
        @Html.ValidationSummary(true)
        
    CourseVM
    @Html.LabelFor(model => model.CourseId)
    @Html.TextBoxFor(model => model.CourseId, new { data_bind = "enable: isInEditMode, value: CourseId" }) @Html.ValidationMessageFor(model => model.CourseId)
    @Html.LabelFor(model => model.CourseName)
    @Html.TextBoxFor(model => model.CourseName, new { data_bind = "enable: isInEditMode, value: CourseName" }) @Html.ValidationMessageFor(model => model.CourseName)
    @Html.LabelFor(model => model.StudentViewModels);
    @Html.ListBoxFor( model => model.StudentViewModels, new SelectList(this.Model.StudentViewModels, "ID", "Name"), new { style = "width: 37%;", data_bind = "enable: isInEditMode, options: StudentViewModels, optionsText: 'Name', value: leftStudentSelected, event: { dblclick: moveFromLeftToRight }" } ) @Html.ListBoxFor( model => model.SelectedStudents, new SelectList(this.Model.SelectedStudents, "ID", "Name"), new { style = "width: 37%;", data_bind = "enable: isInEditMode, options: SelectedStudents, optionsText: 'Name', value: rightStudentSelected, event: { dblclick: moveFromRightToLeft }" } )
    @Html.HiddenFor(model => model.CourseId, new { data_bind="value: CourseId" }) @Html.HiddenFor(model => model.CourseName, new { data_bind="value: CourseName" }) @Html.HiddenFor(model => model.StudentsSerialized, new { data_bind = "value: StudentsSerialized" }) @Html.HiddenFor(model => model.SelectedStudentsSerialized, new { data_bind = "value: SelectedStudentsSerialized" })


    }

    Scripts

    
    
    
    
    
    
    

    Note: I just added these lines:

            @Html.HiddenFor(model => model.CourseId, new { data_bind="value: CourseId" })
            @Html.HiddenFor(model => model.CourseName, new { data_bind="value: CourseName" })
    

    Because when I submit the form my fields are disabled, so the values were not transmitted to the server, that's why I added a couple of hidden fields to do the trick

提交回复
热议问题