Skip to Content
  • Home
  • Book
  • Blog
  • About us
  • Help
  • Contact us
  •  [email protected]
  • Sign in
  • English (US) Español (BO)
  • Simplify It S.R.L.
    • Contact Us
Simplify It S.R.L.
      • Home
      • Book
      • Blog
      • About us
      • Help
      • Contact us
    •  [email protected]
    • English (US) Español (BO)
    • Sign in
    • Contact Us

    Chapter 3: Modern JavaScript Fundamentals, Part I

  • All Blogs
  • OWL Book
  • Chapter 3: Modern JavaScript Fundamentals, Part I
  • August 25, 2026 by
    Chapter 3: Modern JavaScript Fundamentals, Part I
    Grover Menacho

    Why this chapter? I still see junior developers submit code with var and manual for loops on OWL projects — it works, but it fights the language OWL was designed around, and it shows up in every code review. What is Odoo trying to solve with this? OWL 2.0 (and Odoo's own JS codebase) assumes you're comfortable with modern JavaScript — let/const, arrow functions, template literals, and array methods aren't optional extras, they're the baseline the framework's own source code is written in. Real-world application: Every .map()/.filter() you'll write to transform ORM results into something a template can render, and every template literal you'll use to build a dynamic class or message, comes straight from this chapter.

    Now that you know your tools, it's time to learn the language. Modern JavaScript (often called ES6 or newer) introduced powerful features that are now the standard for web development. OWL is built entirely on these modern concepts.

    This chapter and the next are your JavaScript boot camp. We will focus on the absolute essentials you'll use every day when writing OWL components. To keep things clear, all the examples here are plain JavaScript, with no Odoo or OWL code involved. Let's build the foundation.


    Variables Re-imagined: let and const

    For years, JavaScript had only one way to declare a variable: var. It was confusing and had strange behaviors. Modern JavaScript fixed this by giving us two new, much more predictable keywords: let and const.

    let is for variables whose value might need to change later. const is for constants—variables whose value, once assigned, will never change.

    Rule of thumb: Always use const by default. Only use let if you know you will need to reassign the variable. You will almost never need to use the old var.

    // Use let for a variable that will change.
    let score = 0;
    console.log(score); // Outputs: 0
    
    score = 10; // This is allowed.
    console.log(score); // Outputs: 10
    
    // Use const for a value that should not change.
    const playerName = "Alice";
    console.log(playerName); // Outputs: "Alice"
    
    // If you try to change a const, you get an error.
    // playerName = "Bob"; // This would cause an error!
    

    The main advantage of let and const is that they have "block scope," meaning they only exist within the curly braces {} they are defined in. This makes your code much easier to reason about and prevents many common bugs.

    if (true) {
        const message = "Inside the block";
        console.log(message); // Works fine
    }
    
    // console.log(message); // Error! message doesn't exist outside the block
    

    Arrow Functions: A Cleaner Syntax

    Functions are the building blocks of any application. Arrow functions (=>) provide a shorter, cleaner way to write them.

    Here's a traditional function:

    function add(a, b) {
        return a + b;
    }
    

    And here is the exact same function written as an arrow function:

    const add = (a, b) => {
        return a + b;
    };
    

    Even better, if your function is just one line, you can make it even shorter. The return is implicit:

    const subtract = (a, b) => a - b;
    
    console.log(subtract(10, 4)); // Outputs: 6
    

    For functions with just one parameter, you can omit the parentheses:

    const double = x => x * 2;
    const greet = name => `Hello, ${name}!`;
    
    console.log(double(5)); // Outputs: 10
    console.log(greet("Alice")); // Outputs: Hello, Alice!
    

    You will see arrow functions used everywhere in modern JavaScript and OWL code because they are concise and help avoid some tricky issues with the this keyword.


    Template Literals: Building Strings with Power

    One of the most useful features of modern JavaScript is template literals, written with backticks (`) instead of regular quotes. They make creating dynamic strings much easier and more readable.

    The Old Way: String Concatenation

    Before template literals, building dynamic strings was clunky:

    const name = "John Smith";
    const age = 35;
    const department = "Sales";
    
    // The old, painful way
    const message = "Hello, " + name + "! You are " + age + " years old and work in " + department + ".";
    console.log(message);
    // Outputs: Hello, John Smith! You are 35 years old and work in Sales.
    

    The Modern Way: Template Literals

    With template literals, you use backticks and ${} to embed expressions directly in the string:

    const name = "John Smith";
    const age = 35;
    const department = "Sales";
    
    // The modern, clean way
    const message = `Hello, ${name}! You are ${age} years old and work in ${department}.`;
    console.log(message);
    // Outputs: Hello, John Smith! You are 35 years old and work in Sales.
    

    Why Template Literals Are Perfect for OWL

    Template literals are especially useful in OWL development for several reasons:

    1. Dynamic CSS Classes:

    const isActive = true;
    const priority = "high";
    
    const cssClass = `task-item ${isActive ? 'active' : 'inactive'} priority-${priority}`;
    console.log(cssClass); // Outputs: task-item active priority-high
    

    2. Building URLs for RPC calls:

    const recordId = 123;
    const model = "res.partner";
    
    const url = `/web/dataset/call_kw/${model}/read`;
    const searchUrl = `/web/dataset/search_read?model=${model}&ids=[${recordId}]`;
    

    3. Multi-line strings (great for debugging):

    const debugInfo = `
        Component State:
        - Name: ${this.state.name}
        - Active: ${this.state.isActive}
        - Records: ${this.state.records.length}
    `;
    console.log(debugInfo);
    

    4. Dynamic HTML generation (though you'll use templates for this in OWL):

    const createNotification = (type, message) => {
        return `<div class="alert alert-${type}">
            <strong>${type.toUpperCase()}:</strong> ${message}
        </div>`;
    };
    

    Template Literals vs. Regular Strings

    Here's a comparison to show when to use each:

    // Use regular strings for static text
    const staticMessage = "Welcome to Odoo";
    const errorCode = "ERR_404";
    
    // Use template literals when you need dynamic content
    const welcomeMessage = `Welcome back, ${userName}!`;
    const apiEndpoint = `${baseUrl}/api/v1/${resourceType}/${id}`;
    const debugOutput = `Processing record ${recordId} at ${new Date()}`;
    
    // Use template literals for multi-line content
    const emailTemplate = `
        Dear ${customerName},
    
        Your order #${orderNumber} has been ${status}.
    
        Best regards,
        The Odoo Team
    `;
    

    Understanding Objects: The Cornerstone of Data

    An object is a collection of related data and functionality, stored as key-value pairs. This is the most common way you will structure your data in JavaScript. Think of it like a contact card.

    const contact = {
        // key: value
        name: "John Smith",
        email: "[email protected]",
        age: 35,
        isClient: true,
    
        // Objects can also have functions (called methods)
        sayHello() {
            console.log("Hello!");
        }
    };
    
    // You can access data using dot notation.
    console.log(contact.name); // Outputs: "John Smith"
    
    // And call methods the same way.
    contact.sayHello(); // Outputs: "Hello!"
    

    You can also access properties using bracket notation, which is useful when the property name is dynamic:

    const propertyName = "email";
    console.log(contact[propertyName]); // Outputs: "[email protected]"
    
    // This is especially useful with template literals
    const fieldName = "name";
    const value = contact[fieldName];
    const message = `The ${fieldName} field contains: ${value}`;
    

    Objects are fundamental to OWL because a component's state is always an object.


    Mastering Arrays: Working with Lists

    An array is an ordered list of items. It could be a list of numbers, strings, or even other objects.

    const tasks = [
        { id: 1, text: "Write chapter 3", completed: true },
        { id: 2, text: "Create code examples", completed: false },
        { id: 3, text: "Drink coffee", completed: false }
    ];
    

    You will constantly need to transform or filter arrays to display them in your UI. Modern JavaScript gives us powerful methods to do this without writing complicated loops. Here are the three you will use most often:

    .map() - To Transform an Array

    The .map() method creates a new array by transforming every item in the original array. It's perfect for when you want to create a list of UI elements from a list of data.

    // Let's get an array of just the task descriptions.
    const taskTexts = tasks.map(task => task.text);
    
    console.log(taskTexts);
    // Outputs: ["Write chapter 3", "Create code examples", "Drink coffee"]
    
    // Using template literals with map for more complex transformations
    const taskSummaries = tasks.map(task => {
        const status = task.completed ? "Done" : "Pending";
        return `${task.text} - ${status}`;
    });
    
    console.log(taskSummaries);
    // Outputs: ["Write chapter 3 - Done", "Create code examples - Pending", ...]
    

    .filter() - To Select Items from an Array

    The .filter() method creates a new array containing only the items that pass a certain test.

    // Let's get only the tasks that are not yet completed.
    const incompleteTasks = tasks.filter(task => task.completed === false);
    
    console.log(incompleteTasks);
    // Outputs: An array with the "Create code examples" and "Drink coffee" objects.
    
    // More complex filtering with template literals for logging
    const highPriorityTasks = tasks.filter(task => {
        const isIncomplete = !task.completed;
        const isImportant = task.text.includes("coffee"); // Very important!
    
        if (isIncomplete && isImportant) {
            console.log(`Found important task: ${task.text}`);
            return true;
        }
        return false;
    });
    

    .find() - To Get a Single Item from an Array

    The .find() method returns the first item in an array that passes a test. It's useful for finding a specific object by its ID.

    // Let's find the task with id 2.
    const specificTask = tasks.find(task => task.id === 2);
    
    console.log(specificTask);
    // Outputs: { id: 2, text: "Create code examples", completed: false }
    
    // Using find with more complex logic
    const findTaskByPartialText = (searchText) => {
        const foundTask = tasks.find(task => 
            task.text.toLowerCase().includes(searchText.toLowerCase())
        );
    
        if (foundTask) {
            console.log(`Found task: ${foundTask.text}`);
            return foundTask;
        } else {
            console.log(`No task found containing "${searchText}"`);
            return null;
        }
    };
    
    findTaskByPartialText("coffee"); // Will find the "Drink coffee" task
    

    Putting It All Together: A Real-World Example

    Let's combine all these concepts in a practical example that you might encounter in OWL development:

    // Sample data that might come from an Odoo model
    const customers = [
        { id: 1, name: "Acme Corp", email: "[email protected]", isActive: true, totalOrders: 25 },
        { id: 2, name: "Tech Solutions", email: "[email protected]", isActive: false, totalOrders: 8 },
        { id: 3, name: "Global Industries", email: "[email protected]", isActive: true, totalOrders: 42 }
    ];
    
    // Find active customers with more than 10 orders
    const vipCustomers = customers
        .filter(customer => customer.isActive && customer.totalOrders > 10)
        .map(customer => {
            // Create a summary using template literals
            const status = customer.isActive ? "Active" : "Inactive";
            const summary = `${customer.name} (${customer.email}) - ${status} - ${customer.totalOrders} orders`;
    
            return {
                ...customer, // The spread operator copies every property of the original object into this new one, so we don't have to list them all by hand
                summary: summary,
                displayName: `VIP: ${customer.name}`
            };
        });
    
    console.log("VIP Customers:");
    vipCustomers.forEach(customer => {
        console.log(customer.summary);
    });
    
    // This might output:
    // VIP Customers:
    // Acme Corp ([email protected]) - Active - 25 orders
    // Global Industries ([email protected]) - Active - 42 orders
    

    Common Pitfalls

    Confusing .map(), .filter(), and .forEach(). .map() and .filter() both return a new array and are meant to be used with the result (assigned, rendered, chained). .forEach() returns undefined—it's only for running side effects (like console.log) on each item, never for building a new list.

    Mutating the original array or object. tasks.push(...) or contact.name = "..." changes the original data in place. In OWL, mutating a plain object or array directly won't trigger a re-render and can cause subtle bugs elsewhere. Prefer creating new arrays/objects (as .map() and .filter() already do) or using useState, which we'll cover in Chapter 7.

    Using == instead of ===. == converts types before comparing ("5" == 5 is true), which causes confusing bugs. Always use === (and !==) unless you have a specific reason not to.

    Forgetting that const prevents reassignment, not mutation. const contact = {...} means you can't do contact = anotherObject, but you can still do contact.name = "New Name". const only locks the variable binding, not the object's contents.

    Exercises

    1. Write an arrow function formatPrice(amount, currency) that uses a template literal to return a string like "$42.50" (or "42.50 USD" if you prefer a different format).
    2. Given const numbers = [4, 15, 8, 23, 16, 42];, use .filter() to get only the numbers greater than 10, then use .map() to double each of them. Try writing it as one chained expression.
    3. Given the tasks array from this chapter, use .find() to locate the task with id: 3, and log a message that says whether it's completed or not.

    TL;DR: let/const, arrow functions, template literals, and the .map()/.filter()/.find() array methods are the modern JavaScript vocabulary that OWL's own source code — and every example in this book — is written in.

    Try it yourself: This chapter's example is available as an installable Odoo 19 addon: simplifyit_owl_book_ch3_ex1. Installation instructions are in the repository README.


    What's Next?

    Mastering let, const, arrow functions, template literals, objects, and these array methods will give you a solid foundation for building powerful and clean OWL components. In the next chapter, we'll explore more advanced concepts — classes, destructuring, modules, and async/await — that are crucial for understanding how OWL components work internally.

    in OWL Book
    Chapter 4: Modern JavaScript Fundamentals, Part II
    Reading the whole book? Take it with you — free, no sign-up.
    PDF EPUB All chapters
    Useful Links
    • Home
    • About us
    • Blog
    • The OWL 2.0 book
    • Help
    • Contact us
    About us

    Simplify It S.R.L. is an Odoo implementation and development firm based in La Paz, Bolivia, working with companies across Latin America and North America. We have been building on Odoo since version 6.1: custom modules, version migrations and Bolivian localization.

    We are also the authors of the OWL 2.0 book, published free chapter by chapter on our blog.

    Connect with us
    • Contact us
    • [email protected]
    • +591 65144144
    • La Paz, Bolivia
    Follow us
    Copyright © Simplify It S.R.L.
    English (US) | Español (BO)
    Powered by Odoo - Create a free website