The checkbox grid's item size comes from one calculation: container width divided by grid items. Change either side of that equation and the whole layout adjusts. That's the part worth understanding before you touch resize events.
Codecourse
@codecourse.com
We create the most practical screencasts for developers
When a layout needs to react to resize, do you reach for a raw resize listener, ResizeObserver directly, or a wrapper like VueUse's useElementBounding? Each gets you the same width value with a different amount of boilerplate.
Once the batch id lives on the model, checking progress is just fetching the batch and reading its state. No custom progress table, no manual percentage math.
A grid built with a fixed item count works fine until someone resizes the window. Then it just gets cut off. The fix isn't a media query — it's recalculating the grid count from the actual container width.
The payoff of moving batch creation into an observer: a server can get created from a form, a seeder, or an admin panel, and the batch fires the same way every time. No duplicated dispatch logic.
This week: fixing a checkbox grid that breaks on resize, plus a new Getting Started with Laravel episode on form submission. If you've ever hardcoded a grid size, you'll want to see where this goes wrong first.
A batch instance carries more than a database row shows — pending jobs, failure state, cancellation status, all queryable directly off the object Bus::batch() hands back.
Wrap job selection in a factory method keyed by model type rather than branching inside the observer. Keeps the observer readable and makes adding a new entity type a one-file change.
Model observers get a bad reputation for hiding logic, but for "always create a batch when this record exists," they're arguably the least surprising place to put it. Where do you draw the line?
Worth being clear on the difference: Bus::batch() gives you a trackable entity — an ID, progress, cancellation, failure state. Bus::bulk() just dispatches a set of jobs together. Neither replaces the other, they answer different questions.
Storing the batch ID on the model is what makes polling possible later. Fetch the batch by that ID on page load or on an interval, and you've got live progress without extra state to manage.
Getting Started with Laravel is still adding episodes. If you're the one explaining the framework to someone else on the team, it's worth pointing them at codecourse.com.
When a batch has partial failures, do you surface that to the user immediately or wait for the whole batch to finish? Different UX depending on what the batch is actually doing.
->fresh() on a batch instance re-fetches its state from the database. Useful if you're polling — the instance you dispatched with is stale the moment a job in it completes.
A batch instance isn't just a row in job_batches. pendingJobs, cancel(), canceled(), finished(), fresh() — it's a small API for querying and controlling everything in that batch.
queue:work --stop-when-empty-for=60 — idle workers can now wind down automatically instead of sitting there. Directly relevant if your audience is running autoscaling queue infrastructure.
Background job infrastructure keeps coming up as apps lean on queues for AI workloads, imports, anything slow. Batching and tracking that state properly is less optional than it used to be.
Bus::batch() returns the batch instance immediately after dispatch. Assign it to a variable, pull ->id off it, and update your model in the same breath. No second query needed.
Where do you trigger a batch: inside the request/controller that creates the record, or in a model observer listening for the created event? Curious which one people default to and why.
Bus::bulk() shipped in Laravel 13. The batch pattern this week — storing an ID, tracking progress, checking for failures — is deliberate overhead for when you need to know things about a group of jobs after dispatch. If you don't, bulk is the lighter option.
Bus::batch([...]) takes an array of job instances. If different entity types need different jobs, build that array in a factory keyed off the model's type rather than branching inside the observer.
Not every group of jobs needs Bus::batch()'s tracking, cancellation, and callbacks. Bus::bulk() is for when you just want a set dispatched together, nothing more. Worth knowing the difference before reaching for the heavier tool.
Putting Bus::batch() directly in the method that creates a server works, but it couples batch creation to whatever creates the record. A model observer on the created event does the same job without that coupling.
Bus::bulk() landed in Laravel 13. If you've been hand-rolling batch dispatch for a set of jobs that don't need the full batch lifecycle, this is the primitive you actually wanted.
Been running new episodes in Getting Started with Laravel lately — Meet Eloquent, Playing with Request Data. If you've watched either, curious what stood out or what you'd want covered next.
A job batch needs somewhere to live. Add a nullable batch_id column to whatever model triggers it. So you can query progress against that row later instead of guessing.
If you're picking up Laravel for the first time, new episodes are live in Getting Started with Laravel on codecourse.com. No assumed knowledge, just the fundamentals in order.
This week: triggering a job batch and tying it back to a model. A nullable batch_id column, an observer to create the batch, pulling the id back out to store it. Full episode:
Properly triggering a job batch: Job Batching Progress with Laravel
Let’s tackle how to batch tasks in Laravel, change their state as they complete, and...
codecourse.com
DB::prohibitDestructiveCommands(app()->isProduction()) stops db:wipe, migrate:rollback, and migrate:reset from running in production entirely. Not a warning — the command is blocked. Worth adding before you need it.
Running AI workloads inside Laravel queued jobs is one of those things that sounds obvious once you've done it. Keeps the request cycle clean, gives you retry logic for free, and you can monitor everything through Horizon.