【问题标题】:Knockoutjs Multiselect shows index instead of text value when using viewbag使用 viewbag 时,Knockoutjs Multiselect 显示索引而不是文本值
【发布时间】:2017-05-21 18:10:07
【问题描述】:

我正在使用 viewbag 来加载多选列表的选项。但是,当我这样做时,我得到的是一个基于 1 的索引,而不是实际的文本值。

<td> @Html.DropDownList("MAMUserGroupName", (MultiSelectList)ViewBag.MAMUserGroupsList, new { multiple = "multiple", data_bind = "selectedOptions:MAMUserGroups" })</td>

这是视图模型:

    var viewModel = new UserModel([
    {
        id: ko.observable(""), firstName: ko.observable(""), lastName: ko.observable(""),MAMUserGroups: ko.observable()
    }
]);

选择该值并呼叫敲除保存函数时,值为1,2和/或3,而不是实际文本值;在这种情况下,“Group1”、“Group2”、“Group3”

当我这样做时,像这里这样的硬编码选项的标准方式可以按预期工作:Knockout selectedOptions example。但就我而言,我需要从 viewbag 中加载它。

【问题讨论】:

    标签: asp.net-mvc knockout.js viewbag


    【解决方案1】:

    @Html.DropdownList 是列表的服务器端渲染,knockoutjs 是列表的客户端渲染,两者互不了解。您需要做的是将列表呈现到页面上的 javascript 数组,或者通过 Ajax/fetch 从服务器检索它,然后在客户端呈现它。因此,使用您的代码示例,我将用您需要的数据填充您的 knockoutjs 视图模型。类似于以下内容。

    var PageModel = function(data) {
      var users = ko.observableArray();
      var userGroups = ko.observableArray();
    
      var mappedUsers = data.Users.map(function(user) {
        return {
          id: ko.observable(user.id),
          firstName: ko.observable(user.firstName),
          lastName: ko.observable(user.lastName),
          mameUserGroups: ko.observableArray()
        };
      });
    
      users(mappedUsers);
    
      var mappedGroups = data.MAMUserGroups.map(function(item) {
        return {
          id: item.id,
          name: item.name
        };
      });
    
      userGroups(mappedGroups);
    
    
      return {
        users: users,
        userGroups: userGroups
      };
    
    };
    
    
    ko.applyBindings(new PageModel({
      //****** Data loaded here ******
      Users: [{
        id: 1,
        firstName: "test",
        lastName: "user 1"
      }, {
        id: 2,
        firstName: "test",
        lastName: "user 2"
      }, {
        id: 3,
        firstName: "test",
        lastName: "user 3"
      }, {
        id: 4,
        firstName: "test",
        lastName: "user 4"
      }],
      MAMUserGroups: [{
        id: 1,
        name: "User Group 1"
      }, {
        id: 2,
        name: "User Group 2"
      }, {
        id: 3,
        name: "User Group 3"
      }, {
        id: 4,
        name: "User Group 4"
      }]
    }));
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    <table>
      <tbody data-bind="foreach: users">
        <tr>
          <td data-bind="text: firstName"></td>
          <td data-bind="text: lastName"></td>
          <td>
            <select data-bind="options: $parent.userGroups, selectedOptions: mameUserGroups, optionsText: 'name' " size='5' multiple='true'> </select>
          </td>
        </tr>
      </tbody>
    </table>
    
    
    <ul data-bind="foreach: users">
      <li>
        <span data-bind="text: firstName"></span><span data-bind="text: lastName"></span>
        <ul data-bind="foreach: mameUserGroups">
          <li data-bind="text: name"></li>
        </ul>
      </li>
    </ul>
    
    <!--
    <script type="text/javascript">
    // Render the data on the page server side to then be used client side
      $().ready(function(){
        
        var users = @(Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Users)));
        var mamUserGroups =  @(Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.mamUserGroups)));
      });
    </script>
    -->

    编辑 Ajax 实现

    这是一种方法。可能比需要的代码多,但我喜欢将事情分解成单独的责任区域。如果你尝试从这里运行这个 sn-p,你会得到一个错误警报和一个针对用户和用户组的完成警报。

    var app = window.app || {};
    
    
    app.modelMap = (function() {
      function userMap(user) {
        return {
          id: ko.observable(user.id),
          firstName: ko.observable(user.firstName),
          lastName: ko.observable(user.lastName),
          mameUserGroups: ko.observableArray()
        };
      }
    
      function userGroupMap(userGroup) {
        return {
          id: userGroup.id,
          name: userGroup.name
        };
      }
    
    
      return {
        userMap: userMap,
        userGroupMap: userGroupMap
      }
    })();
    
    app.data = (function() {
      function getUserGroups() {
        return $.get("<MAMUSerGroup_URL_HERE>").then(function(data) {
            alert("successfully retrieved user group data");
            return data.map(app.modelMap.userGroupMap);
          })
          .fail(function() {
            alert("error");
          })
          .always(function() {
            alert("finished");
          });
      };
    
      function getUsers() {
        return $.get("<Users_URL_HERE>").then(function(data) {
            alert("successfully retrieved user data");
            return data.map(app.modelMap.userMap);
          })
          .fail(function() {
            alert("error");
          })
          .always(function() {
            alert("finished");
          });
      }
      return {
        getUserGroups: getUserGroups,
        getUsers: getUsers
      }
    })();
    
    app.pageModel = (function() {
      var users = ko.observableArray();
      var userGroups = ko.observableArray();
    
      function getUsers() {
        return app.data.getUsers().done(users);
      }
    
      function getUserGroups() {
        return app.data.getUserGroups().done(userGroups);
      }
    
      function activate() {
        getUsers();
        getUserGroups();
      }
    
      var vm = {
        users: users,
        userGroups: userGroups,
        activate: activate
      };
      return vm;
    })();
    
    
    var vm = app.pageModel;
    vm.activate();
    ko.applyBindings(vm);
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

    【讨论】:

    • 我不能像上面那样对其进行硬编码,因为组列表从服务器端发生了变化。
    • 是的,明白这一点,但您可以做的是在服务器端创建硬编码列表,以便将其传递到客户端,然后 knockoutjs 可以对其进行处理。现在有几种方法可以交付列表。它可以在交付给客户端时呈现在页面上,或者您可以使用 ajax/fetch 路由并查询 webapi 端点以获取数据,然后填充数组。我将看看如何编辑答案以显示我的意思。
    • 让我们用 AJAX 试试吧。我写了一个 AJAX 调用并收到了这个(我只在数组中显示第一个): Array[5] 0:Object MAMUserGroupName:"MAMGroup1" proto:Object 然后我将如何将其映射到我的 viewModel MAMUserGroups?
    猜你喜欢
    • 1970-01-01
    • 2022-01-20
    • 2011-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-14
    • 2016-02-05
    相关资源
    最近更新 更多