Javascript 自定义控件渲染两次

Javascript 自定义控件渲染两次,javascript,sapui5,Javascript,Sapui5,我正在使用自定义控件扩展sap.ui.unified.Calendar,覆盖renderDays函数,以便在每个day div中放置一个额外的span标记 控制台指示小时数数组未定义。它抛出下面发现的错误,但随后继续工作。此错误阻止使用标题箭头在日历中的月份之间移动。这是渲染两次吗?为什么小时数[]最初未定义,但之后可以 如果我将所有代码放在一个文件JSBin中,它不会出错。 自定义控件的代码顶部: sap.ui.unified.Calendar.extend("control.TimeCal

我正在使用自定义控件扩展sap.ui.unified.Calendar,覆盖renderDays函数,以便在每个day div中放置一个额外的span标记

控制台指示小时数数组未定义。它抛出下面发现的错误,但随后继续工作。此错误阻止使用标题箭头在日历中的月份之间移动。这是渲染两次吗?为什么小时数[]最初未定义,但之后可以

如果我将所有代码放在一个文件JSBin中,它不会出错。

自定义控件的代码顶部:

sap.ui.unified.Calendar.extend("control.TimeCalendar", {
    metadata : {
        properties : {
            "hoursData" : "string[]"
        }
    },

  renderer: {
    renderDays: function(oRm, oCal, oDate){
        var hours = oCal.getHoursData();
控制台输出:

Cannot read property 'length' of undefined
摘自自定义控件TimeCalendar.js。这是在do…while循环中,该循环将每天放置在日历上。在函数放置日期的地方,我还包括一个span标记,其中包含从数组“hours”中检索到的数字

oRm.write("<span class=\"sapUiCalDayNum\">");

if ( (hours.length>i) && (hours[i].day == oDay.getUTCDate()) ) {
    oRm.write("<span class=\"hours\">");
    oRm.write(hours[i].hours);
    oRm.write("</span>");
    if(i <= hours.length) { i++; }
}

oRm.write(oDay.getUTCDate());
oRm.write("</span>");

我猜,在非jsbin场景中,您使用的是数据绑定,数据要么从后端异步接收,要么在第一次渲染后设置

在这种情况下,hoursdata值设置为undefined,这会导致错误

如果您这样定义属性:

properties : {
    "hoursData" : { type: "string[]", defaultValue: [] }
}

…这样可以确保始终存在具有长度属性的数组。

谢谢您的帮助。正如您所说,我相信问题在于异步加载。当我将控制器中的模型更改为从同一个文件中定义的变量中读取时,它工作了,而不是指向json文件的url。因此,我将控制器更改为使用loadData,并将async标志设置为false,这解决了问题。后来我改为OData服务,该服务也具有async to false的特性,而且它也起到了作用。几乎在所有情况下,同步加载都是错误的方式——它会阻塞UI线程,并经常导致用户体验不佳。您应该使用默认值并考虑渲染器内部的一些逻辑-例如,在未设置数据时中止,以便在需要时使用异步加载。我理解同步加载是个坏主意。但是,即使使用defaultValue:[]建议,将OData调用更改为异步时,仍然会出现未定义的错误。我已经使用typeof来确定getHoursData的类型,它是一个对象,不是我没有预料到的未定义的对象。在错误发生之前,您仍然可以检查未定义:if!oControl.gethours返回数据;