【问题标题】:Knockout computed column with model用模型淘汰计算列
【发布时间】:2019-06-18 09:35:15
【问题描述】:

我的 MVC C# 解决方案中有一个具有以下属性的模型

public class RegistrationRequirementModel
{
    public string LoadIntent { get; set; }
    public string Francophone { get; set; }
    public string Gender { get; set; }

    public RegistrationRequirementModel(L09RegistrationRequirement requirement)
    {
        LoadIntent = requirement.LoadIntent;
        Francophone = requirement.Francophone;
        Gender = requirement.Gender;
    }
}

在我的 javascript 中,我可以调用模型并显示数据,但是在使用某些计算函数时会失败。

Javascript

    var registrationRequirementModel = {
        frenchData:  ko.observable(""),
        genderData:  ko.observable(""),
        loadIntentData:  ko.observable(""),

        isMissingData: ko.computed(function () {
            if (this.frenchData() == "") { return true };
            if (this.genderData() == "") { return true };
            if (this.loadIntentData() == "") { return true };
            return false;
        },this),

    }

   $(document).ready(function () {

        ko.applyBindings(registrationRequirementModel, document.getElementById("RegistrationSurveyContent"));

        $.ajax({
            url: getStudentRegRequirementsUrl,
            type: "GET",
            contentType: jsonContentType,
            dataType: "json",
            success: function (data) {
                if (!account.handleInvalidSessionResponse(data)) {
                    registrationRequirementModel.frenchData(data.Francophone);
                    registrationRequirementModel.genderData(data.Gender);
                    registrationRequirementModel.loadIntentData(data.LoadIntent);
                }
            },
            error: function (jqXHR, textStatus, errorThrown) {
                if (jqXHR.status != 0)
                    $('#notificationHost').notificationCenter('addNotification', { message: "Unable to retrieve registration requirement.", type: "error" });
            }
        });
    });

HTML

<table style="width:100%">
    <tbody>
        <tr>
            <td data-bind="text: loadIntentData"></td>
            <td data-bind="text: frenchData"></td>
            <td data-bind="text: genderData"></td>
        </tr>
    </tbody>
</table>

目的是在缺少数据时显示html。但是,当我激活此代码时,计算列一直说 frenchData 不是函数。我的观点可以在我的 html data-bind="visible: isMissingData" 中使用。但不幸的是。我可以从我的数据中读取事件。

这是我对 api 的调用

 public async Task<JsonResult> GetRegistrationRequirementAsync()
 {
     string StudentID = CurrentUser.PersonId;
     try
     {
         var requirement = await ServiceClient.L09GetRegistrationRequirementAsync(StudentID);
         RegistrationRequirementModel registrationRequirementModel = new RegistrationRequirementModel(requirement);
         return Json(registrationRequirementModel, JsonRequestBehavior.AllowGet);
      }
      catch (Exception e)
      {}
}

【问题讨论】:

    标签: javascript c# knockout.js knockout-mvc


    【解决方案1】:

    frenchData is not a function 控制台错误源于 KnockoutJS ViewModel 的设置方式。本质上,普通 observables 下面的计算函数 isMissingData 有一个新的内部范围上下文 this,它不反映 registrationRequirementModel 对象的相同外部范围。

    要解决此问题,您应该从使用object literal 切换到constructor function,以便可以将this ViewModel 范围分配给self/that 变量,从而缓解范围问题。然后通过 KO Apply Bindings 实例化您新存储的 ViewModel,您现在可以在 AJAX 成功后访问:

    function registrationRequirementModel() {
      var self = this;
      self.frenchData = ko.observable("");
      self.genderData = ko.observable("");
      self.loadIntentData = ko.observable("");
    
      self.isMissingData = ko.computed(function() {
        if (self.frenchData() == "") {
          return true
        };
        if (self.genderData() == "") {
          return true
        };
        if (self.loadIntentData() == "") {
          return true
        };
        return false;
      }, this);
    }
    
    $(document).ready(function() {
      var vm = new registrationRequirementModel();
      ko.applyBindings(vm, document.getElementById("RegistrationSurveyContent"));
    
      // replace with endpoint
      var jsonData = {
        Francophone: "Francophone",
        Gender: "Male",
        LoadIntent: "LoadIntent"
      };
    
      if (handleInvalidSessionResponse(jsonData)) {
        vm.frenchData(jsonData.Francophone);
        vm.genderData(jsonData.Gender);
        vm.loadIntentData(jsonData.LoadIntent);
      }
    });
    
    function handleInvalidSessionResponse(data) {
      if (typeof data !== "undefined") return true;
      return false;
    }
    

    下面是一个模拟的 JSFiddle 场景 http://jsfiddle.net/ajxrw39m/3/

    【讨论】:

    • 我仍然得到错误,我注意到当我从 ajax 调用 frenchData 时,这就是发生错误的地方
    • 提供您从 AJAX 调用返回的 JSON,以便我们可以使用模拟数据。只有完整的问题才能提供帮助。例如,我们不知道 accountgetStudentRegRequirementsUrl 应该是什么。
    • @Jseb 根据一些假设进行了更新和解决。
    【解决方案2】:

    当您定义视图模型时,this 不指向新创建的对象,它指向您正在创建它的上下文中的任何 this(可能是 window)。

    var vm = {
      computedUsingThis: ko.computed(function() {
        return this;
      }, this)
    }
    
    console.log(
      vm.computedUsingThis() === vm,     // false
      vm.computedUsingThis() === window  // true
    );
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"&gt;&lt;/script&gt;

    有很多方法可以规避这个问题。您可以使用构造函数和new 关键字,或者为视图模型创建工厂方法:

    const VM = () => {
      const a = ko.observable("a");
      const b = ko.observable("b");
      
      const ab = ko.pureComputed(
        () => a() + b()
      );
      
      return { a, b, ab };
    }
    
    const vm = VM();
    vm.ab.subscribe(console.log);
    
    setTimeout(
      () => {
        vm.a("A");
      },
      500
    )
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"&gt;&lt;/script&gt;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-12
      • 2017-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-09
      • 1970-01-01
      相关资源
      最近更新 更多