### Post to Twitter Example Source: https://github.com/mithriljs/mithril.js/wiki/Components Demonstrates how to post content to Twitter using JavaScript. No specific setup is mentioned, but it implies interaction with the Twitter API. ```javascript function postToTwitter() { var url = 'https://twitter.com/intent/tweet'; var text = 'Mithril.js is awesome!'; var shareUrl = url + '?text=' + encodeURIComponent(text); window.open(shareUrl, '_blank'); } ``` -------------------------------- ### Login Form Example Source: https://github.com/mithriljs/mithril.js/wiki/Recipes-and-Snippets A basic login form implementation using Mithril.js. This example demonstrates how to structure a form with input fields and a submit button. ```javascript var LoginForm = { username: '', password: '', view: function() { return m('form', [ m('label', 'Username:'), m('input[type=text]', { oninput: m.withAttr('value', (value) => this.username = value), value: this.username }), m('label', 'Password:'), m('input[type=password]', { oninput: m.withAttr('value', (value) => this.password = value), value: this.password }), m('button[type=submit]', 'Login') ]); } }; m.mount(document.body, LoginForm); ``` -------------------------------- ### Install Mithril.js via npm Source: https://context7.com/mithriljs/mithril.js/llms.txt Install Mithril.js and its TypeScript types using npm for project integration. ```bash # npm npm install mithril --save # TypeScript types npm install @types/mithril --save-dev ``` -------------------------------- ### Video Chooser/Player Example Source: https://github.com/mithriljs/mithril.js/wiki/Components An example that includes a video chooser and player, along with an illustration of paging a long list. This snippet likely demonstrates UI interaction and data handling. ```javascript // Example of paging a long list var list = Array.apply(null, Array(100)).map(function (_, i) { return 'Item ' + (i + 1); }); var pageSize = 10; var currentPage = 1; var paginatedList = { view: function() { var start = (currentPage - 1) * pageSize; var end = start + pageSize; var items = list.slice(start, end); return m('div', [ m('ul', items.map(function(item) { return m('li', item); })), m('div', [ m('button', { onclick: function() { if (currentPage > 1) currentPage--; } }, 'Prev'), m('span', ' Page ' + currentPage + ' of ' + Math.ceil(list.length / pageSize) + ' '), m('button', { onclick: function() { if (currentPage * pageSize < list.length) currentPage++; } }, 'Next') ]) ]); } }; m.mount(document.getElementById('list-container'), paginatedList); ``` -------------------------------- ### Post to Twitter Example (CoffeeScript) Source: https://github.com/mithriljs/mithril.js/wiki/Components Demonstrates how to post content to Twitter using CoffeeScript. This is an alternative to the JavaScript example, implying similar functionality. ```coffeescript # Post to Twitter postToTwitter = -> url = 'https://twitter.com/intent/tweet' text = 'Mithril.js is awesome!' shareUrl = url + '?text=' + encodeURIComponent(text) window.open shareUrl, '_blank' ``` -------------------------------- ### Basic Routing Example in Mithril.js Source: https://github.com/mithriljs/mithril.js/wiki/Recipes-and-Snippets Demonstrates how to switch between different routes within a Mithril.js component. Useful for creating single-page applications with navigation. ```javascript m.route(document.body, "/", { "/": Home, "/about": About, "/contact": Contact }); var root = document.body; m.route(root, "/", { "/": { render: function() { return m("div", "This is the home page.") } }, "/about": { render: function() { return m("div", "This is the about page.") } }, "/contact": { render: function() { return m("div", "This is the contact page.") } } }); ``` -------------------------------- ### Nested Components Example (Deprecated) Source: https://github.com/mithriljs/mithril.js/wiki/Components An example demonstrating nested components in Mithril.js. This example is marked as deprecated and suggests using modern component architecture instead. ```javascript var nestedComponent = { view: function() { return m('div', [ m('h3', 'Parent Component'), m(childComponent) ]); } }; var childComponent = { view: function() { return m('div', 'Child Component'); } }; m.mount(document.body, nestedComponent); ``` -------------------------------- ### Content Editable Example Source: https://github.com/mithriljs/mithril.js/wiki/Recipes-and-Snippets A Mithril.js example demonstrating the use of content editable elements. This snippet shows how to manage the content of an editable div. ```javascript var editableDiv = { view: function(vnode) { return m("div[contenteditable=true]", { oninput: function(e) { vnode.state.content = e.target.innerText; }, innerText: vnode.state.content }); } }; m.mount(document.body, editableDiv); ``` -------------------------------- ### Install Mithril.js TypeScript Definitions Source: https://github.com/mithriljs/mithril.js/blob/main/README.md Install the TypeScript type definitions for Mithril.js from DefinitelyTyped. This is necessary for using Mithril.js with TypeScript. ```bash $ npm install @types/mithril --save-dev ``` -------------------------------- ### Run Mithril.js Tests Source: https://github.com/mithriljs/mithril.js/blob/main/docs/contributing.md Command to execute all tests after installing dependencies. Use `o.only()` to focus on a specific test during debugging. ```bash npm run test ``` ```javascript o.only(description, test) ``` -------------------------------- ### Install Mithril.js via CDN Source: https://github.com/mithriljs/mithril.js/blob/main/README.md Include Mithril.js in your project using a CDN link. Choose between development and production versions, and select your preferred CDN provider (unpkg or jsDelivr). ```html ``` -------------------------------- ### POST with a CORS XHR Source: https://github.com/mithriljs/mithril.js/wiki/Recipes-and-Snippets Example of making a POST request with CORS XHR to avoid preflight OPTIONS conflicts. Useful for cross-origin communication. ```javascript var xhr = m.request({ method: "POST", url: "/foo/bar", data: { "a": 1 }, withCredentials: true, headers: { "Content-Type": "application/x-www-form-urlencoded" } }); ``` -------------------------------- ### Install Mithril.js via npm Source: https://github.com/mithriljs/mithril.js/blob/main/README.md Install Mithril.js as a project dependency using npm. This command adds Mithril.js to your project's node_modules directory and updates your package.json file. ```bash npm install mithril --save ``` -------------------------------- ### Basic CSS Animation in Mithril.js Source: https://github.com/mithriljs/mithril.js/wiki/Recipes-and-Snippets Applies a basic CSS animation to an element within a Mithril.js application. This example shows how to integrate CSS transitions or keyframe animations with Mithril components. ```javascript function AnimatedComponent() { return { view: function() { return m("div", { class: "animated-box" }, "Animate Me"); } } } m.mount(document.body, AnimatedComponent); ``` -------------------------------- ### Checkout and Create Feature Branch Source: https://github.com/mithriljs/mithril.js/blob/main/docs/contributing.md Steps to prepare your local repository for making changes by checking out the main branch and creating a new feature branch. ```bash git checkout main git checkout -b the-feature-branch-name ``` -------------------------------- ### m.route() - Client-side Router Initialization Source: https://context7.com/mithriljs/mithril.js/llms.txt Initialize Mithril's client-side router. Supports path parameters and configurable prefixes. Use programmatic navigation with m.route.set() and read current parameters with m.route.param(). ```javascript const Home = { view: () => m("h1", "Home") } const UserProfile = { view: (vnode) => m("div", m("h1", `User: ${vnode.attrs.id}`), m("p", `Tab: ${vnode.attrs.tab || "overview"}`) ) } const NotFound = { view: () => m("h1", "404 Not Found") } // Change prefix to use real pathnames (requires server-side catch-all) m.route.prefix = "" // Initialize router m.route(document.body, "/", { "/": Home, "/users/:id": UserProfile, "/users/:id/:tab": UserProfile, "/:404...": NotFound, // variadic catch-all }) // Programmatic navigation m.route.set("/users/42") m.route.set("/users/:id", {id: 42}) // with interpolation m.route.set("/users/42", null, {replace: true}) // replace history entry m.route.set("/users/42", null, {state: {from: "home"}}) // push history state // Read current route console.log(m.route.get()) // → "/users/42" // route.param() — read current params (inside a routed component) const UserPage = { view: () => m("p", `id = ${m.route.param("id")}`) } ``` -------------------------------- ### Mount a Component with m.mount() Source: https://context7.com/mithriljs/mithril.js/llms.txt Use m.mount() to render a component into a DOM element and enable automatic redraws. Pass null to unmount. ```js const Counter = { count: 0, view() { return m("div", m("p", `Count: ${Counter.count}`), m("button", { onclick: () => Counter.count++ // triggers automatic redraw }, "Increment"), m("button", { onclick: () => Counter.count-- }, "Decrement") ) } } // Mount to a DOM node m.mount(document.getElementById("app"), Counter) // Unmount (removes DOM content and subscriptions) m.mount(document.getElementById("app"), null) ``` -------------------------------- ### Form Validation with Parsley.js Source: https://github.com/mithriljs/mithril.js/wiki/Recipes-and-Snippets An example of integrating form validation using Parsley.js, including the use of regular expressions for validation rules. ```javascript var form = document.querySelector('form'); var parsley = new Parsley(form); form.addEventListener('submit', function(event) { if (parsley.isValid()) { // Submit form } else { event.preventDefault(); } }); ``` -------------------------------- ### Build Mithril.js Source: https://github.com/mithriljs/mithril.js/blob/main/docs/contributing.md Commands to generate development and minified builds of Mithril.js. ```bash npm run dev ``` ```bash npm run build ``` -------------------------------- ### m.route() — Client-side Router Source: https://context7.com/mithriljs/mithril.js/llms.txt Initializes client-side routing. Routes are keyed by path patterns (supporting :param and :variadic... segments). The default prefix is #! (hashbang) but can be changed. ```APIDOC ## m.route() ### Description Initializes client-side routing. Routes are keyed by path patterns (supporting `:param` and `:variadic...` segments). The default prefix is `#!` (hashbang) but can be changed to pathname or search-based routing. ### Parameters - **root** (DOMElement) - The root DOM element to mount the router to. - **defaultRoute** (string) - The default route to navigate to if no match is found. - **routes** (object) - An object mapping route patterns to components. ### Configuration - **m.route.prefix** (string) - Sets the routing prefix (e.g., `"#!"`, `"/"`). ### Methods - **m.route.set(route, params?, options?)** - Programmatically navigates to a route. - **m.route.get()** - Returns the current route. - **m.route.param(name)** - Reads a current route parameter (inside a routed component). ### Request Example ```javascript const Home = { view: () => m("h1", "Home") } const UserProfile = { view: (vnode) => m("div", m("h1", `User: ${vnode.attrs.id}`), m("p", `Tab: ${vnode.attrs.tab || "overview"}`) ) } const NotFound = { view: () => m("h1", "404 Not Found") } // Change prefix to use real pathnames (requires server-side catch-all) m.route.prefix = "" // Initialize router m.route(document.body, "/", { "/": Home, "/users/:id": UserProfile, "/users/:id/:tab": UserProfile, "/:404...": NotFound, // variadic catch-all }) // Programmatic navigation m.route.set("/users/42") m.route.set("/users/:id", {id: 42}) // with interpolation m.route.set("/users/42", null, {replace: true}) // replace history entry m.route.set("/users/42", null, {state: {from: "home"}}) // push history state // Read current route console.log(m.route.get()) // → "/users/42" // route.param() — read current params (inside a routed component) const UserPage = { view: () => m("p", `id = ${m.route.param("id")}`) } ``` ### Response #### Success Response (200) - **void** - Initializes the router and sets up navigation. ``` -------------------------------- ### m.mount() - Mount a Component to the DOM Source: https://context7.com/mithriljs/mithril.js/llms.txt The `m.mount()` function renders a given component into a specified DOM element and manages its lifecycle, including automatic redraws. Passing `null` as the component will unmount and clean up the element. ```APIDOC ## m.mount() - Mount a Component to the DOM ### Description Renders a component into a real DOM element and subscribes it to automatic redraws. Unmounts the component when `null` is passed as the component. ### Usage `m.mount(element, Component)` ### Parameters - **element** (DOMElement | null) - The DOM element to mount the component to, or `null` to unmount. - **Component** (object | function | null) - The component to mount, or `null` to unmount. ### Examples ```javascript const Counter = { count: 0, view() { return m("div", m("p", `Count: ${Counter.count}`), m("button", {onclick: () => Counter.count++}, "Increment") ) } } // Mount to a DOM node m.mount(document.getElementById("app"), Counter) // Unmount m.mount(document.getElementById("app"), null) ``` ``` -------------------------------- ### Parse and Build URL Pathnames with m.parsePathname and m.buildPathname Source: https://context7.com/mithriljs/mithril.js/llms.txt Use m.parsePathname to extract the path and parameters from a URL. Use m.buildPathname to construct URLs by interpolating parameters into a template, optionally appending remaining parameters as a query string. Supports variadic parameters. ```javascript // Parse pathname + query string m.parsePathname("/users/42?tab=settings#profile") // → {path: "/users/42", params: {tab: "settings"}} m.parsePathname("/search?q=mithril&page=1") // → {path: "/search", params: {q: "mithril", page: "1"}} // Build — interpolate :param tokens, append remainder as query string m.buildPathname("/users/:id/posts", {id: 42, page: 2, sort: "desc"}) // → "/users/42/posts?page=2&sort=desc" m.buildPathname("/api/:resource/:id", {resource: "comments", id: 7}) // → "/api/comments/7" // Variadic parameter (no encoding) m.buildPathname("/files/:path...", {path: "docs/guide/intro.md"}) // → "/files/docs/guide/intro.md" ``` -------------------------------- ### Import Mithril.js Source: https://context7.com/mithriljs/mithril.js/llms.txt Import Mithril.js into your project using CommonJS or ES module syntax. ```js // CommonJS const m = require("mithril") // ES module (bundler) import m from "mithril" ``` -------------------------------- ### Execute Multiple Functions on Event Source: https://github.com/mithriljs/mithril.js/wiki/Recipes-and-Snippets Demonstrates how to execute multiple functions when only one is expected, often useful for event handling. See comments in the original gist for a specific use case. ```javascript m("input", { oninput: [m.withAttr("value", vnode.state.setValue), m.withAttr("value", vnode.state.save)] }); ``` -------------------------------- ### Pathname Utilities Source: https://context7.com/mithriljs/mithril.js/llms.txt Utilities for parsing URL pathnames and query strings into objects, and for building URL pathnames from templates with parameters. ```APIDOC ## m.parsePathname() / m.buildPathname() Parse a URL into `{path, params}`, or interpolate a URL template with parameters, appending leftovers as a query string. ### Usage ```javascript // Parse pathname + query string m.parsePathname("/users/42?tab=settings#profile") // → {path: "/users/42", params: {tab: "settings"}} m.parsePathname("/search?q=mithril&page=1") // → {path: "/search", params: {q: "mithril", page: "1"}} // Build — interpolate :param tokens, append remainder as query string m.buildPathname("/users/:id/posts", {id: 42, page: 2, sort: "desc"}) // → "/users/42/posts?page=2&sort=desc" m.buildPathname("/api/:resource/:id", {resource: "comments", id: 7}) // → "/api/comments/7" // Variadic parameter (no encoding) m.buildPathname("/files/:path...", {path: "docs/guide/intro.md"}) // → "/files/docs/guide/intro.md" ``` ``` -------------------------------- ### Initialize Mithril Component Manually Source: https://github.com/mithriljs/mithril.js/wiki/Helpers-and-Extensions Allows manual creation and management of a component instance for explicit lifecycle control. Useful when you need to control when the controller is initialized. ```javascript m.initComponent = function (component, defaultOptions, defaultContent) { var ctrl = new component.controller(options) ctrl.render = function (options, content) { return component.view( controller, options || defaultOptions, content || defaultContent) } return ctrl } ``` ```javascript var UserList = { controller: function () { /* ... */ }, view: function () { /* ... */ } } var App = { controller: function () { this.userList = m.initComponent(UserList, {users: [ /* ... */ ]}) }, view: function (ctrl) { return m('.app', [ m('h1', "My App"), ctrl.userList.render() ]) } } ``` -------------------------------- ### m.route() with onmatch — Async Route Resolution / Code Splitting Source: https://context7.com/mithriljs/mithril.js/llms.txt Route components can have `onmatch` (async guard/resolver) and `render` (wrapper) hooks, enabling lazy loading and authentication guards. ```APIDOC ## m.route() with onmatch ### Description Route components may be objects with `onmatch` (async guard/resolver) and `render` (wrapper) hooks, enabling lazy loading and authentication guards. ### Route Component Hooks - **onmatch(params, requestedPath, route)**: Called when a route is matched. Can return a component or a Promise resolving to a component. Used for guards and async loading. - **render(vnode)**: A wrapper function that receives the resolved vnode from `onmatch` and can wrap it. ### Request Example ```javascript m.route(document.body, "/login", { "/login": { view: () => m("h1", "Login") }, // Authenticated route with lazy-loaded component "/dashboard": { onmatch(params, requestedPath, route) { if (!localStorage.getItem("token")) { // Redirect to login — returning m.route.SKIP falls through to next route m.route.set("/login") return m.route.SKIP } // Lazy-load the component return import("./Dashboard.js").then(mod => mod.default) }, render(vnode) { return m("main", vnode) // wrap resolved component } }, // Async data preloading "/reports/:id": { onmatch({id}) { return fetch(`/api/reports/${id}`) .then(r => r.json()) .then(data => ({ view: () => m("div", m("h2", data.title), m("p", data.body)) })) } } }) ``` ``` -------------------------------- ### Define a Catch-All Route in Mithril Source: https://github.com/mithriljs/mithril.js/wiki/FAQ Use a route parameter with '...' to define a catch-all route for handling 404s or other unhandled paths. ```javascript m.route(body, '/', { '/': home, '/test': test, '/:...other': my404component }); ``` -------------------------------- ### Mounting a Mithril Component Source: https://github.com/mithriljs/mithril.js/wiki/FAQ Ensures the DOM element exists before rendering. Use Option 1 for direct mounting or Option 2 for deferred mounting on page load. ```html
``` -------------------------------- ### m.fragment() Source: https://context7.com/mithriljs/mithril.js/llms.txt Creates a fragment (grouping of vnodes with no wrapper element). Unlike an array, a fragment can carry a `key` attribute for keyed diffing and lifecycle hooks. ```APIDOC ## m.fragment() ### Description Creates a fragment (grouping of vnodes with no wrapper element). Unlike an array, a fragment can carry a `key` attribute for keyed diffing and lifecycle hooks. ### Method Signature m.fragment(attrs, ...children) ### Parameters #### attrs (object) - **key** (any) - A key attribute for keyed diffing. - Other attributes are passed down to the fragment. #### children (...vnodes) - The child vnodes to be included in the fragment. ### Usage Example ```javascript const items = ["Alpha", "Beta", "Gamma"] m.mount(document.body, { view: () => m("div", // Fragment with a key — safe for use in keyed lists m.fragment({key: "list"}, m("h2", "Items"), items.map((item, i) => m("p", {key: i}, item)) ), // Equivalent using m.Fragment tag string m(m.Fragment, {key: "footer"}, m("hr"), m("small", "End of list") ) ) }) ``` ``` -------------------------------- ### m.vnode - Direct Vnode Construction Source: https://context7.com/mithriljs/mithril.js/llms.txt A low-level factory for creating virtual DOM nodes (vnodes). Prefer using the `m()` hyperscript function for general use. ```APIDOC ## m.vnode — Direct Vnode Construction `m.vnode(tag, key, attrs, children, text, dom)` is the low-level vnode factory. Prefer `m()` for everyday use; this is exposed for advanced cases and library authors. ### Usage ```javascript const Vnode = require("mithril/render/vnode") // Text vnode (tag "#") Vnode("#", undefined, undefined, "Hello", undefined, undefined) // HTML trust vnode (tag "<") Vnode("<", undefined, undefined, "bold", undefined, undefined) // Fragment vnode (tag "[") Vnode("[", "list-key", undefined, [Vnode("#", undefined, undefined, "item")], undefined, undefined) // Normalize a raw value to a vnode Vnode.normalize("plain text") // → text vnode Vnode.normalize(null) // → null (removed from DOM) Vnode.normalize([v1, v2]) // → fragment vnode ``` ``` -------------------------------- ### Create Virtual DOM Nodes with m() Source: https://context7.com/mithriljs/mithril.js/llms.txt Use the m() function to create virtual DOM nodes (vnodes) with selectors, attributes, and children. Supports CSS shorthand and component objects/functions. ```js // Simple element m("h1", "Hello, Mithril!") // →

Hello, Mithril!

// CSS selector shorthand: tag + id + class + attribute m("input#username.form-control[type=text][placeholder=Enter name]", { value: "Alice", oninput: (e) => console.log(e.target.value), }) // → // Nested children m("ul", m("li", {key: 1}, "First"), m("li", {key: 2}, "Second"), m("li", {key: 3}, "Third") ) // → // Dynamic class and inline style const isActive = true m("div", { class: isActive ? "active" : "inactive", style: {color: "red", fontWeight: "bold"}, }, "Styled content") // Component usage (POJO with view) const Button = { view: (vnode) => m("button", {onclick: vnode.attrs.onclick}, vnode.attrs.label) } m(Button, {label: "Click me", onclick: () => alert("clicked!")}) // Functional component function Greeting({attrs}) { return m("p", `Hello, ${attrs.name}!`) } m(Greeting, {name: "World"}) ``` -------------------------------- ### Mithril.js Attribute and Style Case Handling Source: https://github.com/mithriljs/mithril.js/blob/main/render/tests/manual/case-handling.html Demonstrates how Mithril.js handles case sensitivity for data attributes and style properties. Use this to verify correct style updates and attribute retrieval. ```javascript var a = m("div#a", {"data-sampleId": "If you see this message, something is wrong.", style: {backgroundColor: "yellow"}}, "foo") var b = m("div#a", {"data-sampleid": "If you see this message, the update process is correct.", style: {"background-color": "lightgreen"}}, "foo") // background color is yellow m.render(document.getElementById("root"), a) // background color is lightgreen? m.render(document.getElementById("root"), b) // data-sampleid is "If you see this message, the update process is correct."? console.log(document.querySelector("#a").getAttribute("data-sampleid")) ``` -------------------------------- ### m() - Hyperscript / Virtual DOM Node Factory Source: https://context7.com/mithriljs/mithril.js/llms.txt The `m()` function is used to create virtual DOM nodes (vnodes). It accepts a selector string (which can include tag, ID, class, and attributes), an optional attributes object, and child nodes. It also supports functional and object-based components. ```APIDOC ## m() - Hyperscript / Virtual DOM Node Factory ### Description Creates a virtual DOM node (vnode) using hyperscript syntax. Supports HTML tag selectors with CSS shorthand, component objects/functions, attributes, and nested children. ### Usage `m(selector, attrs, ...children)` ### Parameters - **selector** (string | object | function) - HTML tag string with optional CSS shorthand, or a component. - **attrs** (object, optional) - Attributes object for the DOM element or component props. - **children** (...any, optional) - Child nodes, which can be strings, numbers, arrays, or other vnodes. ### Examples ```javascript // Simple element m("h1", "Hello, Mithril!") // Element with ID, class, and attributes m("input#username.form-control[type=text][placeholder=Enter name]", { value: "Alice", oninput: (e) => console.log(e.target.value) }) // Nested children m("ul", m("li", {key: 1}, "First"), m("li", {key: 2}, "Second") ) // Component usage const Button = { view: (vnode) => m("button", {onclick: vnode.attrs.onclick}, vnode.attrs.label) } m(Button, {label: "Click me", onclick: () => alert("clicked!")}) ``` ``` -------------------------------- ### m.route() with onmatch - Async Route Resolution Source: https://context7.com/mithriljs/mithril.js/llms.txt Enable lazy loading and authentication guards for routes using the `onmatch` hook. The `render` hook can wrap the resolved component. ```javascript m.route(document.body, "/login", { "/login": { view: () => m("h1", "Login") }, // Authenticated route with lazy-loaded component "/dashboard": { onmatch(params, requestedPath, route) { if (!localStorage.getItem("token")) { // Redirect to login — returning m.route.SKIP falls through to next route m.route.set("/login") return m.route.SKIP } // Lazy-load the component return import("./Dashboard.js").then(mod => mod.default) }, render(vnode) { return m("main", vnode) // wrap resolved component } }, // Async data preloading "/reports/:id": { onmatch({id}) { return fetch(`/api/reports/${id}`) .then(r => r.json()) .then(data => ({ view: () => m("div", m("h2", data.title), m("p", data.body)) })) } } }) ``` -------------------------------- ### Direct Vnode Construction with m.vnode Source: https://context7.com/mithriljs/mithril.js/llms.txt m.vnode is a low-level factory for creating virtual DOM nodes. It is primarily for advanced use cases and library authors, with m() being the preferred method for everyday component development. It can construct text, HTML trust, and fragment vnodes. ```javascript const Vnode = require("mithril/render/vnode") // Text vnode (tag "#") Vnode("#", undefined, undefined, "Hello", undefined, undefined) // HTML trust vnode (tag "<") Vnode("<", undefined, undefined, "bold", undefined, undefined) // Fragment vnode (tag "[") Vnode("[", "list-key", undefined, [Vnode("#", undefined, undefined, "item")], undefined, undefined) // Normalize a raw value to a vnode Vnode.normalize("plain text") // → text vnode Vnode.normalize(null) // → null (removed from DOM) Vnode.normalize([v1, v2]) // → fragment vnode ``` -------------------------------- ### Creating Keyable Fragments with m.fragment Source: https://context7.com/mithriljs/mithril.js/llms.txt Use m.fragment to group vnodes without a wrapper element. Fragments can have a `key` attribute for efficient diffing in lists. The m.Fragment tag string provides an alternative syntax. ```javascript const items = ["Alpha", "Beta", "Gamma"] m.mount(document.body, { view: () => m("div", // Fragment with a key — safe for use in keyed lists m.fragment({key: "list"}, m("h2", "Items"), items.map((item, i) => m("p", {key: i}, item)) ), // Equivalent using m.Fragment tag string m(m.Fragment, {key: "footer"}, m("hr"), m("small", "End of list") ) ) }) ``` -------------------------------- ### Lifecycle Hooks Source: https://context7.com/mithriljs/mithril.js/llms.txt Mithril components and vnodes support six lifecycle hooks set as attributes: `oninit`, `oncreate`, `onupdate`, `onbeforeupdate`, `onremove`, and `onbeforeremove`. ```APIDOC ## Lifecycle Hooks ### Description Mithril components and vnodes support six lifecycle hooks set as attributes: `oninit`, `oncreate`, `onupdate`, `onbeforeupdate`, `onremove`, and `onbeforeremove`. ### Hooks - **oninit(vnode)**: Fires synchronously during vnode creation, before DOM write. - **oncreate(vnode)**: Fires after DOM node is created and inserted. - **onupdate(vnode, old)**: Fires after every DOM update (not on create). - **onbeforeupdate(vnode, old)**: Fires before DOM update. Return `false` to skip re-render of this subtree. - **onbeforeremove(vnode)**: Fires before removal. Returning a Promise defers DOM removal until it resolves. - **onremove(vnode)**: Fires after the node is removed from DOM. ### Usage Examples ```javascript const AnimatedItem = { view: ({attrs}) => m("div", { // Fires synchronously during vnode creation, before DOM write oninit(vnode) { vnode.state.visible = true }, // Fires after DOM node is created and inserted oncreate(vnode) { vnode.dom.classList.add("fade-in") }, // Fires after every DOM update (not on create) onupdate(vnode) { console.log("DOM updated:", vnode.dom) }, // Return false to skip re-render of this subtree onbeforeupdate(vnode, old) { return vnode.attrs.value !== old.attrs.value }, // Fires before removal; returning a Promise defers DOM removal until it resolves onbeforeremove(vnode) { vnode.dom.classList.add("fade-out") return new Promise(resolve => setTimeout(resolve, 300)) }, // Fires after the node is removed from DOM onremove(vnode) { console.log("Removed:", vnode.dom) }, }, attrs.label) } // Class-based component with lifecycle methods on the instance class Timer { constructor(vnode) { this.interval = null this.ticks = 0 } oncreate(vnode) { this.interval = setInterval(() => { this.ticks++; m.redraw() }, 1000) } onremove(vnode) { clearInterval(this.interval) } view(vnode) { return m("p", `Ticks: ${this.ticks}`) } } m.mount(document.body, Timer) ``` ``` -------------------------------- ### Query String Utilities Source: https://context7.com/mithriljs/mithril.js/llms.txt Utilities for parsing query strings into objects and building query strings from objects. Supports nested objects, arrays, booleans, and URL encoding. ```APIDOC ## m.parseQueryString() / m.buildQueryString() Parse a query string into a nested object, or serialize a (nested) object into a query string. Supports arrays, nested objects, booleans, and URL encoding. ### Usage ```javascript // Parse m.parseQueryString("?name=Alice&role=admin&tags[0]=js&tags[1]=css") // → {name: "Alice", role: "admin", tags: ["js", "css"]} m.parseQueryString("?active=true&count=5&nested[a][b]=deep") // → {active: true, count: "5", nested: {a: {b: "deep"}}} // Build m.buildQueryString({name: "Bob", tags: ["js", "ts"], active: true}) // → "name=Bob&tags%5B0%5D=js&tags%5B1%5D=ts&active=true" m.buildQueryString({filter: {status: "open", priority: "high"}}) // → "filter%5Bstatus%5D=open&filter%5Bpriority%5D=high" // Typical usage with m.request const params = {page: 2, search: "alice", roles: ["admin", "user"]} m.request("/api/users?" + m.buildQueryString(params)) ``` ``` -------------------------------- ### m.request() Source: https://context7.com/mithriljs/mithril.js/llms.txt Sends an XMLHttpRequest or Fetch request. It auto-serializes/deserializes JSON, triggers redraws on completion, and supports custom serialization, response extraction, headers, timeouts, and request configuration. ```APIDOC ## m.request() ### Description Sends an XMLHttpRequest or Fetch request. It auto-serializes/deserializes JSON, triggers redraws on completion, and supports custom serialization, response extraction, headers, timeouts, and request configuration. ### Method Signature m.request(url, options) ### Parameters #### url (string) - The URL to which the request is sent. #### options (object) - **method** (string) - The HTTP method (e.g., 'GET', 'POST'). Defaults to 'GET'. - **body** (any) - The data to send in the request body. Mithril auto-serializes JSON bodies. - **params** (object) - Key-value pairs to interpolate into the URL or append as query parameters. - **type** (constructor) - A constructor function to cast each item in the response array. - **headers** (object) - Custom HTTP headers to send with the request. - **timeout** (number) - The request timeout in milliseconds. - **withCredentials** (boolean) - Whether to send credentials with the request. - **extract** (function) - A function to extract the response data from the XHR object. - **background** (boolean) - If true, the request does not trigger an automatic redraw. - **config** (function) - A function to configure the XHR object before the request is sent. ### Request Examples ```javascript // GET request m.request("/api/users") .then(users => console.log(users)) .catch(err => console.error(err.message, err.code)) // POST with JSON body m.request("/api/users", { method: "POST", body: {name: "Alice", role: "admin"}, }) .then(created => console.log("Created:", created)) // Route parameter interpolation m.request("/api/users/:id/posts", { params: {id: 42, page: 2}, // → GET /api/users/42/posts?page=2 }) // Type casting response class User { constructor(data) { Object.assign(this, data) } } m.request("/api/users", {type: User}) .then(users => users.forEach(u => console.log(u.fullName()))) // Custom headers, timeout, withCredentials m.request("/api/secure", { method: "GET", headers: {"Authorization": "Bearer TOKEN"}, timeout: 5000, withCredentials: true, }) // Custom response extraction m.request("/api/data", { extract(xhr) { return { data: JSON.parse(xhr.responseText), etag: xhr.getResponseHeader("ETag"), } } }) // Background request m.request("/api/ping", {background: true}) // Custom XHR config m.request("/api/upload", { method: "POST", body: new FormData(document.querySelector("form")), config(xhr) { xhr.upload.onprogress = (e) => console.log(e.loaded / e.total * 100 + "%)" return xhr } }) ``` ```