Skip to content

Sponsor

Sponsor

Understanding Parameters and Return Values

What does .update() accept? What does it give you back? This chapter answers both questions — and shows how to use return values for chaining, error checking, and debugging.


Quick Start (30 Seconds)

javascript
// Single element: returns the element itself
const el = Elements.myButton.update({ disabled: true });
el.update({ textContent: 'Loading...' });  // Chain it!

// Bulk update: returns a results object
const results = Elements.update({
  header: { textContent: 'Welcome' },
  subTitle: { textContent: 'Get started' }
});

// Check if updates succeeded
if (results.header.success) {
  console.log('Header updated!');
}

What Is the Parameter?

.update() takes a single parameter: the update object.

javascript
element.update(updateObject);
//              ^^^^^^^^^^^
//              This is the only parameter

The update object is a plain JavaScript object whose keys describe what to change and whose values describe what to set. (For a full breakdown, see the previous chapter on the Update Object.)

What Counts as a Valid Parameter?

InputValid?Behavior
{}✅ YesValid no-op (does nothing)
{ textContent: 'Hi' }✅ YesApplies update
{ style: { color: 'red' } }✅ YesApplies nested update
null⚠️ WarningLogs warning, returns element
'hello'⚠️ WarningLogs warning, returns element
42⚠️ WarningLogs warning, returns element
undefined⚠️ WarningLogs warning, returns element

The method is forgiving: it never throws an error for bad input — it warns and returns gracefully.


Syntax

Form 1: Single Element (via Elements registry)

javascript
Elements.myElement.update(updateObject);
// Returns: the element itself (HTMLElement)

Form 2: Bulk Update (via Elements.update)

javascript
Elements.update({
  elementId1: updateObject1,
  elementId2: updateObject2
});
// Returns: results object { elementId1: {...}, elementId2: {...} }

Form 3: Collection (via Collections.update)

javascript
Collections.update({
  collectionName1: updateObject1,
  collectionName2: updateObject2
});
// Returns: results object { collectionName1: {...}, collectionName2: {...} }

Form 4: Selector Results

javascript
Selector.query('.my-element').update(updateObject);
// Returns: the matched element (or null if no match)

Selector.queryAll('.my-items').update(updateObject);
// Returns: the collection of matched elements

Why Does This Exist?

When Chaining Updates Is Your Priority

The single-element form returns the element itself, enabling clean method chaining:

javascript
Elements.modal.update({ style: { display: 'block' } })
  .update({ classList: { add: 'open' } })
  .update({ setAttribute: { 'aria-hidden': 'false' } });

This approach is great when you need: ✅ Sequential updates where each step builds on the last ✅ Functional pipeline style ✅ To pass the element through utility functions

When Verification Is Your Goal

In scenarios where elements might be missing (dynamic UIs, SPAs, conditional rendering), the bulk update form provides a results object with success/failure info per element:

javascript
const results = Elements.update({
  paymentForm: { style: { display: 'block' } },
  cardInput: { value: '', disabled: false },
  cvvInput: { value: '' }
});

if (!results.paymentForm.success) {
  console.error('Payment form not found!');
  showFallback();
}

This approach is especially useful when: ✅ You need to know which elements were found and which weren't ✅ You're building critical UI flows where missing elements are serious ✅ You want to log or handle errors gracefully without throwing ✅ You're updating elements that might not yet be in the DOM

The Choice Is Yours:

  • Use single-element form when you know the element exists
  • Use bulk form when you need confirmation of success
  • Both approaches return something useful — it's about what you need

Mental Model: The Vending Machine

Think of .update() like a vending machine:

You put in:              You get out:
─────────────            ────────────────────────────
Update object    →       Single element? → Element itself
                 →       Bulk update?   → Dispensed items report
                 →       Bad input?     → Warning + element (no crash)

Single element is like getting your drink directly — you get back the thing you put in your money for, ready to use.

Bulk update is like getting a vending report — "Item A: dispensed ✅, Item B: out of stock ❌" — so you know exactly what happened.


How Does It Work?

Single Element Return

Elements.myButton.update({ disabled: true })


┌─────────────────────────────────────┐
│  Process update object              │
│  Apply each property/handler        │
│  Change detection: skip if same     │
└─────────────────────────────────────┘


   return element   ←── The actual HTMLElement


Elements.myButton.update({ disabled: true }).update({ textContent: '...' })
                         ↑ chaining works because element is returned

Bulk Update Return

Elements.update({ header: {...}, footer: {...} })


┌─────────────────────────────────────────────┐
│  For each key in the bulk object:           │
│    1. Look up element by ID                 │
│    2. If found: apply update, mark success  │
│    3. If not found: mark failure with error │
└─────────────────────────────────────────────┘


{
  header: {
    success: true,
    element: <HTMLElement>,
    error: null
  },
  footer: {
    success: false,
    element: null,
    error: 'Element not found: footer'
  }
}

The Return Values in Detail

Single Element Return Value

When you call .update() on an element directly, you get the element itself back:

javascript
const element = Elements.myButton.update({ textContent: 'Click me' });

// element === the actual HTMLElement
element instanceof HTMLElement;  // true
element === Elements.myButton;   // true

// So you can immediately call any DOM method
element.focus();
element.scrollIntoView();

// Or chain another update
element.update({ disabled: false });

When the element doesn't exist:

javascript
const element = Elements.nonExistent.update({ textContent: 'Hi' });
// element: null (the element wasn't found)

Always handle the null case for optional elements:

javascript
const el = Elements.optionalBanner?.update({ textContent: 'Welcome' });
if (el) {
  el.focus();
}

Bulk Update Return Value

When you call Elements.update({}) with an object (the bulk form), you get a results object:

javascript
const results = Elements.update({
  header: { textContent: 'Hello' },
  missing: { textContent: 'World' }  // Doesn't exist in DOM
});

// results looks like:
{
  header: {
    success: true,          // Was the element found & updated?
    element: HTMLElement,   // The actual element (or null)
    error: null             // Error message (or null)
  },
  missing: {
    success: false,
    element: null,
    error: 'Element not found: missing'
  }
}

Results Object Properties

PropertyTypeDescription
successbooleantrue if element was found and update was applied
elementHTMLElement | nullThe found element, or null if not found
errorstring | nullError description if success is false

Deep Dive: Using Return Values Effectively

Pattern 1: Simple Chaining

The most common use of the return value:

javascript
// Chain sequential updates
Elements.myInput
  .update({ value: '' })
  .update({ disabled: false })
  .update({ focus: [] });

// Or combine them (even better):
Elements.myInput.update({
  value: '',
  disabled: false,
  focus: []
});

Pattern 2: Storing the Element for Later

javascript
// Capture the element for repeated use
const button = Elements.submitBtn.update({
  textContent: 'Submit',
  disabled: false
});

// Use it multiple times
setTimeout(() => {
  button.update({ disabled: true });
}, 3000);

Pattern 3: Checking Critical Element Existence

javascript
async function showPaymentForm() {
  const results = Elements.update({
    paymentForm: { style: { display: 'block' } },
    cardNumber: { value: '', disabled: false },
    expiryDate: { value: '' },
    cvvCode: { value: '' }
  });

  // Check all critical elements exist
  const allFound = Object.values(results).every(r => r.success);

  if (!allFound) {
    const missing = Object.entries(results)
      .filter(([, r]) => !r.success)
      .map(([id]) => id);

    console.error('Missing elements:', missing);
    showErrorPage('Payment form unavailable');
    return;
  }

  // Safe to proceed — all elements found
  results.cardNumber.element.focus();
}

Pattern 4: Partial Success Handling

javascript
const results = Elements.update({
  primaryContent: { textContent: data.main },
  secondaryContent: { textContent: data.secondary },
  sidebar: { textContent: data.sidebar }
});

// Handle each result individually
if (!results.primaryContent.success) {
  // This is critical — abort
  throw new Error('Primary content area missing');
}

if (!results.secondaryContent.success) {
  // This is optional — log and continue
  console.warn('Secondary content not found, skipping');
}

if (!results.sidebar.success) {
  // This is optional — use a fallback
  console.info('Sidebar not available');
}

Pattern 5: Logging for Debugging

javascript
const results = Elements.update({
  header: { textContent: 'New Title' },
  nav: { classList: { add: 'active' } },
  footer: { textContent: 'Footer text' }
});

// Log all results
Object.entries(results).forEach(([id, result]) => {
  if (result.success) {
    console.log(`✅ Updated: ${id}`);
  } else {
    console.warn(`❌ Failed: ${id} — ${result.error}`);
  }
});

Pattern 6: Functional Pipeline

javascript
function applyLoadingState(elementId) {
  return Elements[elementId].update({
    disabled: true,
    textContent: 'Loading...',
    classList: { add: 'loading' }
  });
  // Returns the element — can be further processed
}

function applyReadyState(element) {
  return element.update({
    disabled: false,
    textContent: 'Submit',
    classList: { remove: 'loading' }
  });
}

// Pipeline: applyLoadingState → wait → applyReadyState
const btn = applyLoadingState('submitBtn');
setTimeout(() => applyReadyState(btn), 2000);

Deep Dive: Return Values in Collection Updates

When updating a collection (multiple elements sharing a class/group), the behavior differs:

javascript
// Update a collection of buttons — returns the collection itself
const buttons = Collections.allButtons.update({
  disabled: true,
  classList: { add: 'inactive' }
});

// buttons is the collection — you can chain collection methods
buttons.update({ textContent: 'Disabled' });

Bulk collection updates (via Collections.update({})) also return a results object:

javascript
const results = Collections.update({
  navLinks: { classList: { remove: 'active' } },
  menuItems: { disabled: false }
});

// results.navLinks.success — was the collection found?
// results.navLinks.element — the collection (not a single element)

Common Mistakes and How to Fix Them

Mistake 1: Ignoring Return Value for Chaining

javascript
// ❌ WRONG — can't chain after this
Elements.myBtn.update({ textContent: 'Hi' });
               .update({ disabled: false });  // Error! No element returned to chain

// ✅ CORRECT — chain directly
Elements.myBtn
  .update({ textContent: 'Hi' })
  .update({ disabled: false });

Mistake 2: Not Checking Results for Critical Elements

javascript
// ❌ WRONG — silent failure if element missing
Elements.update({
  paymentForm: { style: { display: 'block' } }
});
// Continues even if paymentForm doesn't exist

// ✅ CORRECT — verify critical elements
const { paymentForm } = Elements.update({
  paymentForm: { style: { display: 'block' } }
});

if (!paymentForm.success) {
  throw new Error('Payment form not found');
}

Mistake 3: Assuming Element Exists After Update

javascript
// ❌ WRONG — element might be null
const el = Elements.myElement.update({ textContent: 'Hi' });
el.focus();  // TypeError if el is null!

// ✅ CORRECT — guard against null
const el = Elements.myElement.update({ textContent: 'Hi' });
el?.focus();  // Optional chaining — safe

Mistake 4: Confusing Single vs Bulk Return

javascript
// ❌ WRONG — expecting bulk result from single update
const result = Elements.myButton.update({ disabled: true });
result.myButton.success;  // TypeError! result is the HTMLElement

// ✅ CORRECT — use bulk form for results object
const results = Elements.update({
  myButton: { disabled: true }
});
results.myButton.success;  // Works!

Quick Reference: Return Value Summary

Call form                                    Returns
──────────────────────────────────────────   ────────────────────────────────
Elements.myEl.update({...})                  HTMLElement (or null)
Elements.update({ id1: {}, id2: {} })        { id1: {success, element, error} }
Collections.myCol.update({...})              Collection
Collections.update({ col1: {}, col2: {} })   { col1: {success, element, error} }
Selector.query('...').update({...})          HTMLElement (or null)
Selector.queryAll('...').update({...})       Collection

Summary

Understanding parameters and return values gives you full control over .update():

  • One parameter: the update object (plain {})
  • Forgiving input: won't throw on bad input, logs warning
  • Single element form returns the element itself — enabling chaining
  • Bulk form returns a results object — enabling verification
  • Results object has { success, element, error } per element ID
  • Null handling: elements not found return null from single form, success: false from bulk
  • Chain pattern: use for sequential or functional-style updates
  • Verification pattern: use for critical UI paths where element existence matters

What's Next?

Next chapter: Update Properties Deep Dive — a complete reference for every property category you can include in an update object.