视图

视图部件

视图部件在Odoo的注册分类为view_widgets。

列表视图

WC的列表视图(ListView)指的是视图(view)、控制器(controller)和渲染器(Renderer)三个部分。下面我们来逐一看以下这三个部分。

渲染器(Renderer)

我们来看渲染器的定义:

export class ListRenderer extends Component {
    static template = "web.ListRenderer";
    static rowsTemplate = "web.ListRenderer.Rows";
    static recordRowTemplate = "web.ListRenderer.RecordRow";
    static groupRowTemplate = "web.ListRenderer.GroupRow";
    static useMagicColumnWidths = true;
    static LONG_TOUCH_THRESHOLD = 400;
    static components = { DropdownItem, Field, ViewButton, CheckBox, Dropdown, Pager, Widget };
    static defaultProps = { hasSelectors: false, cycleOnTab: true };
    static props = [
        "activeActions?",
        "list",
        "archInfo",
        "openRecord",
        "onAdd?",
        "cycleOnTab?",
        "allowSelectors?",
        "editable?",
        "onOpenFormView?",
        "hasOpenFormViewButton?",
        "noContentHelp?",
        "nestedKeyOptionalFieldsData?",
        "optionalActiveFields?",
    ];
    ...
}

从定义我们可以看到列表视图被分成了4个视图模板来分别渲染。整体部件使用的是ListRenderer视图,其中的每一列使用的是Rows模板,有数据的行使用的是RecordRow, 分组视图使用的是GroupRow

启动方法

接下来我们看以下启动方法(Setup):

setup() {
    this.uiService = useService("ui");
    this.notificationService = useService("notification");
    const key = this.createViewKey();
    this.keyOptionalFields = `optional_fields,${key}`;
    this.keyDebugOpenView = `debug_open_view,${key}`;
    this.cellClassByColumn = {};
    this.groupByButtons = this.props.archInfo.groupBy.buttons;
    useExternalListener(document, "click", this.onGlobalClick.bind(this));
    this.tableRef = useRef("table");

    this.longTouchTimer = null;
    this.touchStartMs = 0;
    ...

}

方法很长,这里我们逐一来看。

this.creates = this.props.archInfo.creates.length
            ? this.props.archInfo.creates
            : [{ type: "create", string: _t("Add a line") }];

this.cellToFocus = null;
this.activeRowId = null;
onMounted(async () => {
    // Due to the way elements are mounted in the DOM by Owl (bottom-to-top),
    // we need to wait the next micro task tick to set the activeElement.
    await Promise.resolve();
    this.activeElement = this.uiService.activeElement;
});
onWillPatch(() => {
    const activeRow = document.activeElement.closest(".o_data_row.o_selected_row");
    this.activeRowId = activeRow ? activeRow.dataset.id : null;
});
this.optionalActiveFields = this.props.optionalActiveFields || {};
this.allColumns = [];
this.columns = [];
onWillRender(() => {
    this.allColumns = this.processAllColumn(this.props.archInfo.columns, this.props.list);
    Object.assign(this.optionalActiveFields, this.computeOptionalActiveFields());
    this.debugOpenView = exprToBoolean(browser.localStorage.getItem(this.keyDebugOpenView));
    this.columns = this.getActiveColumns(this.props.list);
    this.withHandleColumn = this.columns.some((col) => col.widget === "handle");
});

creates

我们在第二部分讲过列表视图中可以添加Add按钮,现在我们来看一下具体的实现。首先我们来看视图定义:

<t t-foreach="creates" t-as="create" t-key="create_index">
    <a
        t-if="create.type === 'create'"
        href="#"
        role="button"
        t-att-class="create_index !== 0 ? 'ml16' : ''"
        t-att-tabindex="props.list.editedRecord ? '-1' : '0'"
        t-on-click.stop.prevent="() => this.add({ context: create.context })"
    >
        <t t-esc="create.string"/>
    </a>
    <ViewButton
        t-if="create.type === 'button'"
        className="`${create.className} ${create_index !== 0 ? 'ml16' : ''}`"
        clickParams="create.clickParams"
        icon="create.icon"
        record="props.list"
        string="create.string"
        title="create.title"
        tabindex="props.list.editedRecord ? '-1' : '0'"
    />
</t>

xml部分的代码印证我们之前的结论,列表控制器中只能添加两种类型的按钮。接下来我们看js代码部分:

this.creates = this.props.archInfo.creates.length
            ? this.props.archInfo.creates
            : [{ type: "create", string: _t("Add a line") }];

this.creates属性用来存储列表视图中的Add系列按钮。如果视图中的creates按钮为空,那么给一个默认类型为create的Add a line的按钮。xml代码中指明了单击事件的处理方法add:

add(params) {
    if (this.canCreate) {
        this.props.onAdd(params);
    }
}

先检查当前列表是否能够创建新记录,如果可以,则使用props属性的onAdd方法来添加一条新记录。params从定义的context中而来,用户可以指定不同的默认值,也可以自定义自己的实现。

results matching ""

    No results matching ""