简体   繁体   中英

Populate textbox using knockout “data-bind=click”

I wonder if you could help. Just starting using KnockoutJS and I have a problem with populating textboxes based on a selected . I am sure this is very obvious to the well-trained eyes but I can't seem to locate the cause of the problem. Below is my implementation.

public class RoleViewModel
{
    public int RoleID { get; set; }
    public string RoleName { get; set; }
    public string Description { get; set; }
    public int ApplicationID { get; set; }
    public string ApplicationName { get; set; }

}

public class RoleIndexViewModel
{
    public List<RoleViewModel> RolesList { get; set; }
    public RoleViewModel Rvm { get; set; }
}

Index.cshtml below

@model ExpensesOrganiser4.ViewModels.RoleIndexViewModel

@section scripts{
    @Scripts.Render("~/bundles/jqueryval")
    @Scripts.Render("~/bundles/jqueryui")
    <script src="~/Scripts/knockout-2.1.0.js" type="text/javascript"></script>
    <script src="~/Scripts/knockout.mapping-latest.js" type="text/javascript"></script>
    <script src="~/Scripts/Application/role.js" type="text/javascript"></script>
    <script type="text/javascript">
        RoleVM.ViewModel = ko.mapping.fromJS(@Html.Raw(Json.Encode(Model)));
    </script>
}

<table>
    <tr>
        <th>@Html.DisplayNameFor(model => model.Rvm.RoleName)</th>
        <th>@Html.DisplayNameFor(model => model.Rvm.Description)</th>
        <th>@Html.DisplayNameFor(model => model.Rvm.ApplicationName)</th>

   </tr>

@foreach (var item in Model.RolesList) {
    <tr data-bind="click: GetSelectedRole" id="updtr">
        <td>@Html.DisplayFor(modelItem => item.RoleName)</td>
        <td>@Html.DisplayFor(modelItem => item.Description)</td>
        <td>@Html.DisplayFor(modelItem => item.ApplicationName)</td>
    </tr>
}
</table>

<table data-bind="visible: ReadOnlyMode">
<tr>
    <td><label for="RoleID">Role ID:</label></td>
    <td><input data-bind="value: RoleID()" type="text" id="RoleID" /></td>
</tr>
<tr>
    <td><label for="RoleName">Role Name:</label></td>
    <td><input data-bind="value: RoleName()" type="text" id="RoleName" /></td>
</tr>
<tr>
    <td><label for="Description">Role Description:</label></td>
    <td><input data-bind="value: Description()" type="text" id="Description" /></td>
</tr>
<tr>
    <td><label for="ApplicationName">Application:</label></td>
    <td><input data-bind="value: ApplicationName()" type="text" id="ApplicationName" /></td>
</tr>
</table>

Definition for Knockout

var RoleVM = {
EditFields: ko.observable(false),
ReadOnlyMode: ko.observable(true),
DisplayEditRoleButton: ko.observable(true),
DisplayUpdateRoleButton: ko.observable(false),
RoleID: ko.observable($("#RoleID").val()),
RoleName: ko.observable($("#RoleName").val()),
OriginalRoleName: ko.observable($("#RoleName").val()),
Description: ko.observable($("#Description").val()),
OriginalDescription: ko.observable($("#Description").val()),
ApplicationName: ko.observable($("#ApplicationName").val()),
OriginalApplicationName: ko.observable($("#ApplicationName").val()),
MessageBox: ko.observable(""),
SelectedRow: ko.observable(),
GetSelectedRole: function (roleData) {
    RoleVM.RoleID(roleData.RoleID);
    RoleVM.RoleName(roleData.RoleName);
    RoleVM.Description(roleData.Description);
    RoleVM.ApplicationName(roleData.ApplicationName);
}
};

function roleData(data) {
this.RoleID = ko.observable(data.RoleID);
this.RoleName = ko.observable(data.RoleName);
this.Description = ko.observable(data.Description);
this.ApplicationName = ko.observable(data.ApplicationName);
}


ko.applyBindings(RoleVM);

When I click on the , I get the following in the textbox

function c(){if(0<arguments.length){if(!c.equalityComparer||!c.equalityComparer
(d,arguments[0]))c.I(),d=arguments[0],c.H();return this}a.U.La(c);return d}"

I know if I call an observable, I need to call it as a function but when I did the following, the textbox contains empty string.

GetSelectedRole: function (roleData) {
    RoleVM.RoleID(roleData.RoleID());
    RoleVM.RoleName(roleData.RoleName());
    RoleVM.Description(roleData.Description());
    RoleVM.ApplicationName(roleData.ApplicationName());
}

Any advice is deeply appreciated. Thanks

I'm not sure where the data in your current solution can come from so I've made a couple of adjustments.

Firstly I recommend following the pattern of using a function for viewmodels of any complexity as it tends to make things easier.

var RoleVM = function () {
    var self = this;
    self.EditFields = ko.observable(false);
    self.ReadOnlyMode = ko.observable(true),
    self.DisplayEditRoleButton = ko.observable(true),
    self.DisplayUpdateRoleButton = ko.observable(false),
    self.RoleID = ko.observable($("#RoleID").val()),
    self.RoleName = ko.observable($("#RoleName").val()),
    self.OriginalRoleName = ko.observable($("#RoleName").val()),
    self.Description = ko.observable($("#Description").val()),
    self.OriginalDescription = ko.observable($("#Description").val()),
    self.ApplicationName = ko.observable($("#ApplicationName").val()),
    self.OriginalApplicationName = ko.observable($("#ApplicationName").val()),
    self.MessageBox = ko.observable(""),
    self.SelectedRow = ko.observable(),
    self.GetSelectedRole = function (roleId, roleName, description, applicationName) {
        self.RoleID(roleData.RoleId);
        self.RoleName(roleData.RoleName);
        self.Description(roleData.Description);
        self.ApplicationName(roleData.ApplicationName);
    }
};

You would bind this as follows:

ko.applyBindings(new RoleVM());

Then you can call GetSelectedRole using a wrapper function so that you can pass your data in using some Razor.

@foreach (var item in Model.RolesList) {
    <tr data-bind="click: function () { GetSelectedRole(@item.RoleID, @item.RoleName, @item.Description, @item.ApplicationName) }" id="updtr">
        <td class="role-name">@Html.DisplayFor(modelItem => item.RoleName)</td>
        <td class="description">@Html.DisplayFor(modelItem => item.Description)</td>
        <td class="application-name">@Html.DisplayFor(modelItem => item.ApplicationName)</td>
    </tr>
}

In your solution you have GetSelectedRole bound to the click event of the row. When the click event is fired it calls GetSelectedRole with two parameters, data (your viewmodel) and eventArgs. You have a function called rollData which is never called, as it is hidden by the parameter of the same name inside GetSelectedRole . Therefore you are setting your viewmodel's observable values to the observable itself. So in essence you have a nested observable, so when you are trying to get the observable value it is returning you another observable which when converted to string shows you the observable wrapper function which you see in your text box.

Try changing it like this

data-bind="click: GetSelectedRole.bind($data)"

Also change your function using this

GetSelectedRole: function (roleData) {
    this.RoleID(roleData.RoleID);
    this.RoleName(roleData.RoleName);
    this.Description(roleData.Description);
    this.ApplicationName(roleData.ApplicationName);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM