-
Notifications
You must be signed in to change notification settings - Fork 2.6k
XAFR - Technical Trainin 8000 g #740
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 18.0
Are you sure you want to change the base?
Conversation
estate/__manifest__.py
Outdated
An application module that aims to serve as an onboarding sandbox. | ||
""", | ||
'application': "True", | ||
} No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't forget to always add an empty line at the end of your files :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I updated and I'll do that in the future. Why do I need to add that empty line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is one of the PEP8 recommendations
estate/models/estate_property.py
Outdated
name = fields.Char('Title', required=True, translate=True) | ||
description = fields.Text('Description') | ||
postcode = fields.Integer('Postcode', help="Your post code in 4 or 5 digits.") | ||
date_availability = fields.Date('Date Availability') | ||
expected_price = fields.Float('Expected Price', required=True) | ||
selling_price = fields.Float('Selling Price') | ||
bedrooms = fields.Integer(string='Bedrooms') | ||
living_area = fields.Integer('Living Area (sqm)') | ||
facades = fields.Integer('Facades') | ||
garage = fields.Boolean('Garage') | ||
garden = fields.Boolean('Garden') | ||
garden_area = fields.Integer('Garden Area (sqm)') | ||
garden_orientation = fields.Selection( | ||
string='Garden Orientation', | ||
selection=[('north', 'North'), ('west', 'West'), ('south', 'South'), ('east', 'East')], | ||
help="The selection of the garden orientation.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All good but most of the field display names are not required.
If not set, Odoo will basically deduct the display name of the field based on the field name. It'll separate it on the underscore and capitalize every word. (In case of a Many2One, Many2Many or One2Many behaviour will be slightly different but we'll see that when you'll have some). For example:
description -> Description
expected_price -> Expected Price
Basically, except name
, living_area
and garden_area
none of them are required to be explicitly mentioned. Not a big issue but helps code look cleaner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok thank you that's good to know :)
…ing message on db launch, also removed code from estate_property.py because it was clutter that will be added in chapter 10)
46f80ea
to
92195f6
Compare
estate/models/__init__.py
Outdated
from . import estate_property | ||
from . import estate_property_type | ||
from . import estate_property_tags | ||
from . import estate_property_offer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing newline at the end of file (CI indicated it as well)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok yeah I missed that one thank you for pointing it out
copy=False, | ||
default='new', | ||
selection=[('new', 'New'), ('offer_received', 'Offer Received'), ('offer_accepted', 'Offer Accepted'), ('sold', 'Sold'), ('cancelled', 'Cancelled')]) | ||
property_type_id = fields.Many2one("estate.property.type", string="Property Type") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you now have a Many2One as example, I can explain how it works.
If you follow the naming correctly, Odoo can generate the correct name here as well:
property_type_id
will give Property Type
For One2many, same should happen:
offer_ids
will become Offers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok great to know :)
Added property models offer, type and tags
3a7900e
to
a5ea174
Compare
selection=[('accepted', 'Accepted'), ('refused', 'Refused')], | ||
copy=False,) | ||
partner_id = fields.Many2one("res.partner", string="Partner", required=True) | ||
property_id = fields.Many2one("estate.property", string="Offer", required=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a nasty copy paste (string still indicates it's an Offer 😄). Same for these Many2ones
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually named it offer_id
at first but then the instructions said to name it property_id
and it ended up not being displayed anyway.. Should I just omit string="..."
as much as possible and try to rely on the automated system from odoo you referenced here: #740 (comment) ?
from odoo import fields, models | ||
|
||
|
||
class EstateTagsModel(models.Model): |
There was a problem hiding this comment.
Choose a reason for hiding th 6855 is comment
The reason will be displayed to describe this comment to others. Learn more.
We try to follow the _name
for naming a class. This should be EstatePropertyTag
(keep it singular as well)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I realized afterward that I had pluralized everything. I'll fix it in the next push and also I indeed forgot a word
from odoo import fields, models | ||
|
||
|
||
class EstateTypeModel(models.Model): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EstatePropertyType
Added property computed fields and onchange
0ca24e8
to
93b7190
Compare
Added action buttons logic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments about chapter 8
|
||
|
||
class EstateOfferModel(models.Model): | ||
class EstatePropertyOfferModel(models.Model): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should leave out the Model
in the class name :)
for record in self: | ||
if record.create_date: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be merged as one line
for record in self.filtered("create_date"'):
Sorry, something went wrong.
All reactions
-
👍 1 reaction
for record in self: | ||
if record.create_date: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same about merging to one line
Sorry, something went wrong.
All reactions
-
👍 1 reaction
def _inverse_deadline(self): | ||
for record in self: | ||
if record.create_date: | ||
record.validity = (record.date_deadline - fields.Date.to_date(record.create_date)).days |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure you need to convert the record.create_date
? 🤔
If it is about it being a datetime
rather than a date, record.create_date.date()
is cleaner IMO
Sorry, something went wrong.
All reactions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I originally went about it that way because on the Odoo documentation about Date and Datetime fields, the suggested method (and only one that I found to convert from date to datetime) was to use to_date
...
But yeah this is much cleaner thank you! :)
Sorry, something went wrong.
All reactions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Chapter 9 comments
Sorry, something went wrong.
All reactions
estate/models/estate_property.py
Outdated
if record.state != 'cancelled': | ||
record.state = "sold" | ||
else: | ||
raise UserError("This property is already cancelled and thus cannot be sold anymore.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing bad with this code but, if you use _()
method it'll be able to handle translations.
raise UserError(_("This property is already cancelled and thus cannot be sold anymore."))
Sorry, something went wrong.
All reactions
-
👍 1 reaction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I get used to adding _()
for any field that is user facing?
Sorry, something went wrong.
All reactions
estate/models/estate_property.py
Outdated
if record.state != 'sold': | ||
record.state = "cancelled" | ||
else: | ||
raise UserError("This property is already sold and thus cannot be cancelled anymore.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same about translation
Sorry, something went wrong.
All reactions
-
👍 1 reaction
def action_btn_accept(self): | ||
for record in self: | ||
record.status = "accepted" | ||
record.property_id.buyer_id = self.partner_id.id | ||
record.property_id.selling_price = self.price | ||
return True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When designing such actions you need to think about the usecase. Will you run this method on more than one record at a time? In this case as it is displayed in a list view that is inside a form, it won't.
You can then use a self.ensure_one()
at the begining to check that it is being run on a single record (not 0 nor more than 1).
If you still want to keep the loop, you should be careful as you're looping over self
and assigning a value to record
but yet using self.partner_id.id
and self.price
. If you have more than one partner_id
or different price
it'll raise an error.
Also, don't forget to update the property state record.property_id.state = 'offer_accepted'
Sorry, something went wrong.
All reactions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see! Thank you for the correction. I'll try and think further ahead
Sorry, something went wrong.
All reactions
Constraints
e01239a
to
6ee2a07
Compare
Add the sprinkles Fixes according to review comments
e6ca176
to
b4b888b
Compare
6B28
Inheritance
b4b888b
to
1742244
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review chapter 11 & 12
Sorry, something went wrong.
All reactions
awesome_gallery/__manifest__.py
Outdated
Starting module for "Master the Odoo web framework, chapter 3: Create a Gallery View" | ||
""", | ||
|
||
'author': "unknown", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But why? At least put Odoo if you have to fill something
Sorry, something went wrong.
All reactions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just wanted to get rid of the warning messages but yeah should have put odoo. I'm changing it now.
Sorry, something went wrong.
All reactions
|
||
name = fields.Char('Title', required=True, translate=True) | ||
line_ids = fields.One2many("estate.property", "property_type_id") | ||
manual_ordering = fields.Integer('Sequence', default=1, help="Used to order stages. Lower is better.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally we'd call the field sequence
as it is something we have quite a bit in the standard code. But it is not a big issue
Sorry, something went wrong.
All reactions
-
👍 1 reaction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted and corrected :)
Sorry, something went wrong.
All reactions
line_ids = fields.One2many("estate.property", "property_type_id") | ||
manual_ordering = fields.Integer('Sequence', default=1, help="Used to order stages. Lower is better.") | ||
offer_ids = fields.One2many("estate.property.offer", "property_type_id") | ||
offer_count = fields.Integer(compute='_compute_offers') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By convention the compute should include the name of the computed field.
_compute_offer_count
should be the one here 😄
Sorry, something went wrong.
All reactions
-
👍 1 reaction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted and fixed
Sorry, something went wrong.
All reactions
.run/rd-demo.run.xml
Outdated
<component name="ProjectRunConfigurationManager"> | ||
<configuration default="false" name="rd-demo" type="Odoo" factoryName="Odoo"> | ||
<module name="tutorials" /> | ||
<option name="ENV_FILES" value="" /> | ||
<option name="INTERPRETER_OPTIONS" value="" /> | ||
<option name="PARENT_ENVS" value="true" /> | ||
<envs> | ||
<env name="PYTHONUNBUFFERED" value="1" /> | ||
</envs> | ||
<option name="SDK_HOME" value="$PROJECT_DIR$/../../../virtualenvs/18.0/bin/python/" /> | ||
<option name="WORKING_DIRECTORY" value="" /> | ||
<option name="IS_MODULE_SDK" value="true" /> | ||
<option name="ADD_CONTENT_ROOTS" value="true" /> | ||
<option name="ADD_SOURCE_ROOTS" value="true" /> | ||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" /> | ||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/../../../worktrees/saas-18.3/odoo/odoo-bin" /> | ||
<option name="PARAMETERS" value="-c $PROJECT_DIR$/.odev/training_odoo.conf -u awesome_owl,awesome_clicker,awesome_gallery,awesome_dashboard,awesome_kanban,estate" /> | ||
<option name="SHOW_COMMAND_LINE" value="false" /> | ||
<option name="EMULATE_TERMINAL" value=" D375 true" /> | ||
<method v="2" /> | ||
</configuration> | ||
</component> No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not necessary 😄
Sorry, something went wrong.
All reactions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I understand. I tried to add it to the .gitignore
but it did not work and I did not want to unselect it everytime I made a new push.. 😬
I will still add it to the .gitignore
Sorry, something went wrong.
All reactions
estate/models/estate_property.py
Outdated
|
||
@api.ondelete(at_uninstall=False) | ||
def _unlink_if_new_or_cancelled_property(self): | ||
if any(estate_property.state in ['offer_received', 'offer_accepted', 'sold'] for estate_property in self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine but know that you can do this like this as well:
if self.filtered(lambda ep: ep.state in ['offer_received', 'offer_accepted', 'sold']):
or
if {'offer_received', 'offer_accepted', 'sold'}.intersect(set(self.mapped('state'))):
Sorry, something went wrong.
All reactions
-
👍 1 reaction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a preferred one? If so what is the priority order / where can I find it? 🤔
Sorry, something went wrong.
All reactions
estate/models/res_users.py
Outdated
class ResUsers(models.Model): | ||
_inherit = "res.users" | ||
|
||
property_ids = fields.One2many("estate.property", "salesman_id", domain="") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't add domain
if you don't plan to use it
Sorry, something went wrong.
All reactions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch I was supposed to add a domain there then forgot about it. I will fix that and upload in the next push.
Sorry, something went wrong.
All reactions
Inter-module interactions
Inter-module interactions Optimized code to correct a DRY violation that led to unnecessary calls and wasted compute power. Co-authored-by: Sébastien Dieu <118258604+sedi-odoo@users.noreply.github.com>
3215a94
to
6a42330
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Chapter 13 comments
Sorry, something went wrong.
All reactions
.gitignore
Outdated
.pyre/ | ||
|
||
# PyCharm Demo Config | ||
.run/rd-demo.run.xml |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EOL 😅
Good thing to add it to the .gitignore
. But as the file is already tracked, git won't care about this.
You should run git update-index --skip-worktree .run/rd-demo-run.xml
(can be done on any file you wan't to refresh the tracking on).
(Best way would be to remove the file and then put it back after having removed it with a commit but let's just keep this as is now)
Sorry, something went wrong.
All reactions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see ok I'll fix it using the last method that's usually how I do it too :)
Sorry, something went wrong.
All reactions
# @SEDI J'ai pas réussi à faire fonctionner avec la plus simple que tu as suggérée. Elle return res.partner(3,) au lieu de res.partner() comme l'autre mais du coup ça marche pas.. | ||
# partner_id = self.salesman_id.partner_id | ||
partner_id = self.env['estate.property'].browse(self.env.context.get('active_id')).salesman_id.partner_id | ||
invoicing_price = self.selling_price * 0.06 | ||
|
||
values = { | ||
'partner_id': partner_id, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What error did you get? I think you'd just need to replace 'partner_id': partner_id
by 'partner_id': partner_id.id
Sorry, something went wrong.
All reactions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok that worked thank you :)
Sorry, something went wrong.
All reactions
-
👍 1 reaction
QWeb Templates
Coding Guidelines Review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Chapters 14 & 15
Sorry, something went wrong.
All reactions
<field name="view_mode">list,form</field> | ||
<field name="context">{'search_default_availability': True}</field> | ||
<field name="view_mode">list,form,kanban</field> | ||
<!-- <field name="context">{'search_default_availability': True}</field>--> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to leave a commented line :)
Sorry, something went wrong.
All reactions
-
👍 1 reaction
Best Offer: | ||
<field name="best_offer"/>€ | ||
</div> | ||
<div t-if="record.state.raw_value == 'offer_accepted'"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should use a t-elif
here
Sorry, something went wrong.
All reactions
-
👍 1 reaction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes indeed
Sorry, something went wrong.
All reactions
estate/models/estate_property.py
Outdated
if tools.float_utils.float_compare((record.expected_price * 0.9), record.selling_price, precision_rounding=0.01) >= 0 and not tools.float_utils.float_is_zero(record.selling_price, precision_rounding=0.001): | ||
raise ValidationError(_("Offer price cannot be lower than 90% of the expected price.")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather have an import that is
from odoo.tools.float_utils impot float_compare, float_is_zero
That will make the code more readable IMO
Sorry, something went wrong.
All reactions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok yeah makes sense :)
Sorry, something went wrong.
All reactions
estate/models/estate_property.py
Outdated
@api.ondelete(at_uninstall=False) | ||
def _unlink_if_new_or_cancelled_property(self): | ||
if any(estate_property.state in ['offer_received', 'offer_accepted', 'sold'] for estate_property in self): | ||
raise UserError("Can't delete a property that is not new of cancelled!") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't forget the translation 😄
Sorry, something went wrong.
All reactions
-
👍 1 reaction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, fixed it! :)
Sorry, something went wrong.
All reactions
self.property_id.buyer_id = self.partner_id.id | ||
self.property_id.selling_price = self.price | ||
self.property_id.state = 'offer_accepted' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be done with a write
and a dict
self.property_id.write({
'buyer_id': self.partner_id.id,
'selling_price': self.price,
'state': 'offer_accepted'
})
Sorry, something went wrong.
All reactions
-
👍 1 reaction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated! I will try to go about it that way in the future
Sorry, something went wrong.
All reactions
for record in self: | ||
record.status = "refused" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can just be done with records.status = "refused"
no need to loop on them
Sorry, something went wrong.
All reactions
-
👍 1 reaction
<field name="res_model">estate.property</field> | ||
<field name="view_mode">list,form,kanban</field> | ||
<!-- <field name="context">{'search_default_availability': True}</field>--> | ||
<field name="context">{'search_default_availability': True}</field> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guess that eludes my review on that part 😄
Sorry, something went wrong.
All reactions
-
👍 1 reaction
Owl Components
2955b71
to
27cf297
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Chapter 1 JS comments
Sorry, something went wrong.
All reactions
[options] | ||
addons_path = /home/odoo/odev/worktrees/18.0/odoo/addons,/home/odoo/odev/worktrees/18.0/enterprise,/home/odoo/odev/worktrees/18.0/design-themes,/home/odoo/odev/repositories/odoo-ps/tutorials | ||
db_name = web_tutorial | ||
limit_time_cpu = 999999 | ||
limit_time_real = 999999 | ||
limit_memory_hard = 0 | ||
log_handler = odoo.addons.base.models.ir_attachment:WARNING | ||
http_port = 8069 | ||
gevent_port = 8072 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not necessary to commit this 😛
Sorry, something went wrong.
All reactions
import { Component, useState, markup } from "@odoo/owl"; | ||
import { Counter } from "../counter/counter"; | ||
import {TodoList} from "../todo/todo_list"; | ||
import {TodoItem} from "../todo/todo_item"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Be consistent on the format of your imports
Sorry, something went wrong.
All reactions
awesome_owl/static/src/card/card.js
Outdated
|
||
static components = { Counter }; | ||
|
||
static template = "awesome_owl.card" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should start component names by a capital letter
static template = "awesome_owl.Card"
Sorry, something went wrong.
All reactions
<t t-slot="default"> | ||
<Counter/> | ||
</t> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the purpose of this part of the tutorial is to create a slot and populate it from outside the component
Basically you should not have the Counter inside of this component but rather in the Playground
Sorry, something went wrong.
All reactions
<t t-out="html_bloc_1"/> | ||
<t t-out="html_bloc_2"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will 47CD be displayed to describe this comment to others. Learn more.
Same about this, tutorial said to use the markup in the playground
Sorry, something went wrong.
All reactions
|
||
<t t-name="awesome_owl.counter"> | ||
<div> | ||
<button class="btn btn-primary" t-on-click="increment">Referenced XML Button</button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not Increment
instead of Referenced XML Button
?
Sorry, somet C3F3 hing went wrong.
All reactions
|
||
export class TodoItem extends Component { | ||
|
||
static template = "awesome_owl.todo_item" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static template = "awesome_owl.TodoItem"
Sorry, something went wrong.
All reactions
<?xml version="1.0" encoding="UTF-8" ?> | ||
<templates xml:space="preserve"> | ||
|
||
<t t-name="awesome_owl.todo_item"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<t t-name="awesome_owl.TodoItem">
Sorry, something went wrong.
All reactions
|
||
<t t-name="awesome_owl.todo_item"> | ||
<div t-att-class="{'text-muted': props.todo.isCompleted, 'text-decoration-line-through': props.todo.isCompleted}"> | ||
<input type="checkbox" t-att-checked="props.todo.isCompleted" t-on-change="toggleCheckBox" style="margin-right: 5px"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's one way of doing it, know that you could also have done this for the t-on-change
t-on-change="() => props.todo.isCompleted = !props.todo.isCompleted"
or better, you can call a method on the todo (if you move it to a JS class)
Sorry, something went wrong.
All reactions
this.input = useRef("keyboard_input"); | ||
onMounted(() => { | ||
this.input.el.focus(); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Weren't you supposed to use useAutofocus
instead?
Sorry, something went wrong.
All reactions
Build a dashboard
Build a dashboard
Reviewers
sedi-odoo
Assignees
No one assignedLabels
Projects
Milestone
No milestoneDevelopment
Successfully merging this pull request may close these issues.
A PR to log and facilitate the review of the completed chapters.