Search code examples
xmlxpathodooodoo-11odoo-view

Change button's action dynamically


Can a button's action be changed dynamically depending on another field's value? Example code:

<xpath expr="//button[@class='oe_stat_button o_res_partner_tip_opp']" position="attributes">
    <attribute name="name">%(action1)d</attribute>
    <attribute name="name">%(action2)d</attribute>
</xpath>

That button's action would be action1 or action2 depending on, let's say, a boolean/select/whatever field's value. How can this be achieved?


Solution

  • There are at least two possibilities:

    Create multiple buttons and show or hide them by condition

    In the end it should look like:

    <field name="my_selection_field" />
    <button name="%(action1)d" string="Action 1" attrs="{'invisible': [('my_selection_field', '!=', 'selection1')]}" />
    <button name="%(action2)d" string="Action 2" attrs="{'invisible': [('my_selection_field', '!=', 'selection2')]}" />
    <button name="%(action3)d" string="Action 3" attrs="{'invisible': [('my_selection_field', '!=', 'selection3')]}" />
    

    It's obviously not the perfect solution, but it should work.

    Use a python method returning an action

    That will work, too, but will be a bit more dynamic. Just make the button of type object and set a model multi record method in the name attribute.

    <button action="button_dynamic_action" string="Action" type="object" />
    

    And now implement that method on the views model:

    @api.multi
    def button_dynamic_action(self):
        self.ensure_one()
        action = {}
        if self.my_selection_field == 'selection1':
            action = {
                'name': _('Action 1'),
                'view_type': 'form',
                'view_mode': 'form',
                'res_model': 'my.model',
                #'view_id': # optional
                'type': 'ir.actions.act_window',
                #'res_id': # optional
                'target': 'new' # or 'current'
            }
        elif self.my_selection_field == 'selection2':
            action = {
                'name': _('Action 2'),
                'view_type': 'form',
                'view_mode': 'tree',
                'res_model': 'my.model',
                #'view_id': # optional
                'type': 'ir.actions.act_window',
                #'res_id': # optional
                'target': 'current' # or 'new'
            }
        # and so on
        return action
    

    You can also read from already existing window actions (ir.actions.act_window) instead of "creating" them in code, following example is from Odoo itself:

    res = self.env['ir.actions.act_window'].for_xml_id('base', 'action_attachment')
    # ... change res with context or name and so on
    return res