Call methods and functions directly in expressions — arguments are tracked, this is bound to the immediate owner, and return values participate in the reactive graph.
What it means
You can call any method or function in an expression string: multiply(a), b.multiply(a), cart.byId(id).qty. rs-x treats function call nodes like any other expression node — dependencies on arguments and on the function owner are tracked, and results update automatically when those dependencies change.
Practical value
No manual wiring is needed to include a function return value in a reactive graph. Pass a reactive field as an argument and the call re-evaluates when that field changes. Replace the owner object and the call re-evaluates against the new owner. The expression string is the complete specification.
Key points
Arguments are tracked: if a reactive field is passed as an argument, the call re-evaluates when that field changes.
this is always bound to the immediate owner object, so b.multiply(a) binds this to b.
Dynamic dispatch is supported: b[b.methodName](a) re-evaluates when methodName changes, not just when a changes.
Function calls can be chained: cart.first().qty — the return value becomes the owner for the next member access segment.
Zero-argument calls are supported: initializeA() — side-effect calls work and the result (including undefined) is tracked.
Basic method call example
Call a method on the root model object. The expression re-evaluates automatically when the argument field changes.
import{emptyFunction,InjectionContainer,WaitForEvent}from'@rs-x/core';import{rsx,RsXExpressionParserModule}from'@rs-x/expression-parser';awaitInjectionContainer.load(RsXExpressionParserModule);constmodel={a:10,multiplyWithTwo(x:number){return2*x;},};// Expression calls the method and tracks the argument 'a'constexpr=rsx<number>('multiplyWithTwo(a)')(model);awaitnewWaitForEvent(expr,'changed').wait(emptyFunction);console.log(expr.value);// 20// Changing 'a' causes the call to re-evaluateawaitnewWaitForEvent(expr,'changed',{ignoreInitialValue:true}).wait(()=>{model.a=5;});
Nested method call with this binding example
Call a method on a nested object where this refers to that nested object. Re-evaluates when the owner object is replaced.
import{emptyFunction,InjectionContainer,WaitForEvent}from'@rs-x/core';import{rsx,RsXExpressionParserModule}from'@rs-x/expression-parser';awaitInjectionContainer.load(RsXExpressionParserModule);constmodel={a:10,b:{x:3,multiply(factor:number){returnthis.x*factor;// 'this' is bound to 'b'},},};constexpr=rsx<number>('b.multiply(a)')(model);awaitnewWaitForEvent(expr,'changed').wait(emptyFunction);console.log(expr.value);// 30// Replacing the owner 'b' re-evaluates the call against the new objectawaitnewWaitForEvent(expr,'changed',{ignoreInitialValue:true})
Dynamic dispatch example
Select the method at runtime via a computed member name: b[b.methodName](a). Re-evaluates when the method name field changes.
import{emptyFunction,InjectionContainer,WaitForEvent}from'@rs-x/core';import{rsx,RsXExpressionParserModule}from'@rs-x/expression-parser';awaitInjectionContainer.load(RsXExpressionParserModule);constmodel={a:10,b:{methodName:'multiply'as'multiply'|'add',multiply(x:number){return3*x;},add(x:number){return3+x;},},};// The method name itself comes from another reactive fieldconstexpr=rsx<number>('b[b.methodName](a)')(model);awaitnewWaitForEvent(expr,'changed').wait(emptyFunction);console.log(expr.value);// 30 (multiply: 3 * 10)// Changing 'methodName' selects a different methodawaitnewWaitForEvent(expr,'changed',{ignoreInitialValue:true})
Chained call example
The return value of a function call becomes the owner of the next member access: cart.first().qty.
import{emptyFunction,InjectionContainer,WaitForEvent}from'@rs-x/core';import{rsx,RsXExpressionParserModule}from'@rs-x/expression-parser';awaitInjectionContainer.load(RsXExpressionParserModule);constmodel={cart:{items:[{qty:1},{qty:2}],first(){returnthis.items[0];},},};// Return value of first() becomes the owner of .qtyconstexpr=rsx<number>('cart.first().qty')(model);awaitnewWaitForEvent(expr,'changed').wait(emptyFunction);console.log(expr.value);// 1awaitnewWaitForEvent(expr,'changed',{ignoreInitialValue:true}).wait(()=>{model.cart.items[0].qty=4;});console.log(expr.value);// 4