Upload
others
View
2
Download
0
Embed Size (px)
Citation preview
A Single Page App Using the Odoo JS Frameworka.k.a “Odoo JS Development for Dummies”
Damien BOUVY • R&D Developper
EXPERIENCE
2017
Introduction1
Odoo JS 101
Odoo JS Utils (usable outside of the web client)
Live Coding Demo
Now what?
2
3
4
5
I’ll go make my own web client!1
— Some manager to one of his backend team
We need a JS app for this particular project and no one from the JS team is available.
Odoo JS Framework
Models Views* (* and more)
Class(.js)
require(‘web.Class’)
Qweb(.js)
require(‘web.core’).qweb
Widget(.js)
require(‘web.Widget’)
Can we build a small MV* Web App using the Odoo Framework?
=> Yes!
Wait a minute!
Odoo JS FrameworkModern JS libs/frameworks
MV*-like ✅ ✅
Templating ✅ ✅
Community modules /web, OCA? npm
Two-way binding“Reactive” Nope ✅ (often)
Packaging tools Not reallyManual bundles \o/
Webpack, babel, etc.
Perks Odoo-compatible OoB Light, Trendy, etc.
Odoo JS != VueJS, React, etc.
Odoo JS 1012Base JS classes, architecture
Odoo JS ModuleBaby steps
odoo.define('demo.module', function (require) { // <== define here
'use strict';
var Class = require('web.Class'); // <== import here
var AbstractThingy = Class.extend({
// do abstract stuff
});
var RealThingy = BaseThingy.extend({
//do real stuff
});
return RealThingy; // <== export here
});
Class.jsHey kids, want some OOP?
var Class = require('web.Class');
var Ticket = Class.extend({
init: function (values) {
Object.assign(this, values);
},
});
var MagicTicket = Ticket.extend({
init: function (values) {
this._super.apply(this, arguments);
this.magic = this.init_magic();
},
init_magic: function () {
// do stuff
},
});
Widget.jsIf you mess your lifecycle, you’re gonna have a bad time
var Widget = require('web.Widget');
var Component = Widget.extend({
template: 'demo.template',
events: {},
init: function () { // synchronous
this._super.apply(this, arguments);
},
willStart: function () { // asynchronous, pre-render
return this._super.apply(this, arguments).then(function () {
})
}
start: function () {} // asynchronous, post-render - use super as well!
});
QWeb(.js)Javascriptify ALL the things!
var Widget = require('web.Widget');
var qweb = core.qweb;
var Component = Widget.extend({
template: 'demo.thingies_list',
thingies: [],
});
// ... or ...
var template = 'demo.thingies_lit';
var eval_context = {thingies: thingies};
var content = qweb.render(template,
eval_context);
<t t-name="demo.thingies_list">
<t t-if="(widget.)thingies.length">
<ul>
<t t-foreach="(widget).thingies"
t-as="thingy">
<t t-call="demo.thingy"/>
</t>
</ul>
</t>
<p t-else="">No tickets to see</p>
</t>
Parent Widget
Child Widget
Init with all necessary data
Main Widget
Child WidgetChild Widget
(custom) events public functionsCommunication flow
- Events for upward communication
- Direct calls for downward communication
Components hierarchy
- Parent-unaware children- Children-aware parents
Architecture in a nutshell
Odoo JS Utils3Usable outside the web client
Backend Communication (1)rpc = require('web.rpc');
fetchTicket: function (id) {
var self = this;
return rpc.query({
model: 'demo.ticket',
method: 'search_read',
args: [[['id', '=', id]]],
kwargs: {fields: ['id', 'name', 'description']}
}).then(function (ticket_values) {
if (ticket_values.length) {
var ticket = new Ticket(ticket_values[0]);
self.tickets.push(ticket);
}
return ticket;
});
},
Backend Communicationrpc = require('web.rpc');
fetchRouteThingy: function (some_info) {
var self = this;
return rpc.query({
route: '/thingies/custom_route',
params: {foo: some_info}
}).then(function (result) {
var foo = self.do_something(result);
return foo;
});
},
Dialogsvar Dialog = require(‘web.Dialog’)
new Dialog(this, {
title: _t('New Ticket'),
$content: qweb.render('ticket_viewer.ticket_form'),
buttons: [{
text: _t('Submit Ticket'),
close: true,
click: function () {
self._onFormSubmit();
},
}],
}).open();
Notification Centervar notification = require('web.notification');
// In Main widget
custom_events: {
'ticket-submit': '_onTicketSubmit',
'warning': function (ev) {this.notification_manager.warn(ev.data.msg);},
'notify': function (ev) {this.notification_manager.notify(ev.data.msg);},
},
// In start() override:
self.notification_manager = new notification.NotificationManager(self);
self.notification_manager.appendTo(self.$el);
// In any child
this.trigger_up('warning', {msg: _t('All fields are mandatory')});
Longpolling (1)from odoo.addons.bus.controllers.main import BusController
from odoo.addons.bus.controllers.main import BusController
class TicketController(BusController): def _poll(self, dbname, channels, last, options): """ Add the relevant channels to the BusController polling. """ if options.get('demo.ticket'): channels = list(channels) ticket_channel = ( request.db, 'demo.ticket', options.get('demo.ticket') ) channels.append(ticket_channel) return super(TicketController, self)._poll(dbname, channels, last, options)
Python code required!
Longpolling (2)var bus = require('bus.bus').bus;
// In start() override:
bus.on('notification', self, self._onNotification);
// Handler
_onNotification: function (notifications) {
for (var notif of notifications) {
var channel = notif[0], message = notif[1];
if (channel[1] !== 'demo.ticket' || channel[2] !== this.user.partner_id) {
return; }
if (message[0] === 'unlink_ticket') {
this.user.removeTicket(message[1]);
this.list.removeTicket(message[1]);
}
}
},
// After starting the main widget
bus.start_polling();
Live Coding Demo4Bus IntegrationNotification Manager
Frontend Routing
Bonus
The age of # is behind us
Frontend [email protected]('/app/<path:route>')
@route('/tickets/<path:route>', auth='user')def view_tickets(self, **kwargs): tickets = request.env['demo.ticket'].search([]) return request.render('ticket_viewer.ticket_list', {'tickets': tickets})
Python code required!
Routing library required :-)
Now What?5
Some resources
General Javascript● jQuery Promises (e.g. https://www.sitepoint.com/introduction-jquery-deferred-objects/)● Standard JS: Mozillla Developper Network https://developer.mozilla.org �● Know you DevTools: https://developer.chrome.com/devtools (Source, Network tabs are a
must - don’t forget debug=assets)● Like, a ton of good blogs/websites:
○ David Walsh - https://davidwalsh.name/ �○ Sitepoint - https://www.sitepoint.com/javascript/○ PonyFoo - https://ponyfoo.com/○ Medium.com (although currently more about VueJS, React, etc.)○ Just Google It :)
Odoo Specific● /addons/web/static/src/js/core (commented, dosctringed, etc.)
○ class.js○ dialog.js○ rpc.js○ widget.js○ … explore.○ Use this as your main resource!
● Online Documentation: not at the moment● “The Odoo JS Framework” - Gery Debongnie (Odoo Framework team leader)
○ Today at 4.30pm in this very room● Code from this demo: https://github.com/dbo-odoo/odoo-js-demo
Repo for this talk: [email protected]/dbo-odoo/odoo-js-demo.git
Start coding!It’s easy
JS can be fun
Quick results
Nice for beginners
Thank you.
#odooexperience
EXPERIENCE
2017