IMPORTANT:
I’m explaining this problem from an “ember” point of view, still, this solution fits multiple frameworks and is a general fix to get materialize parallax working – stay tuned!
If you know web frameworks, you know the dreaded word
DEPRECATED
from any log at any time, everywhere!
Some time ago i encountered a familiar error message while updating an ember project:
using this.$() in a component has been deprecated, consider using this.element
Ember 3.9 deprecation (2019)
[deprecation id: ember-views.curly-components.jquery-element]
To read a detailed description on the reason this deprecation was introduced and the details on upgrading on it, please click the link in the quotation, it’ll lead you to deprecations.emberjs.com
The actual reasoning behind this change is not relevant for the fix that i’m going to introduce.
Anyhow, this change affected the parallax background(s) on my webpage, it didn’t break anything, but it would surely introduce a problem on the long run, so i was going to update the deprecated line.
The line looked like this:
this.$(‘.parallax’).parallax();
The full deprecation warning looked like this:
deprecate.js:136
DEPRECATION:
Using this.$() in a component has been deprecated, consider using this.element [deprecation id: ember-views.curly-components.jquery-element]
See https://deprecations.emberjs.com/v3.x#toc_jquery-apis for more details.
I looked all around and found a solution on the original materialize documentation (and copies of this solution on the StackOverflow)
So i applied the “fix” and replaced my line with this:
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.parallax');
var instances = M.Parallax.init(elems, options);
});
The above code implies that you somehow import “M” from materialize css, which would add this entry to the top of the page:
import M from ‘materialize.css’;
And you know what?
It didn’t work.
I didn’t get an error, and i didn’t get a parallax.
The page was just showing no background…
The next thing to check was how Materialize’s JavaScript was loaded. In my setup it was available as window.M. Ember does not provide that global automatically: it depends on the app’s asset imports or add-on. A CSS import alone does not provide the JavaScript API.
So ok, we throw out the import.
The code still doesn’t work.
A component can be inserted long after DOMContentLoaded has fired. In a classic Ember component, initialise DOM-dependent plugins in didInsertElement and clean them up in willDestroyElement. A delayed later() callback is not, by itself, a guarantee that the right component is present.
So we import “later” and change the code, like following:
import { later } from ‘@ember/runloop’;
later(()=>{
var elems = document.querySelectorAll(‘.parallax’);
window.M.Parallax.init(elems, options);});
nope, still a white background, nothing parallaxy going on here.
So then, something caught our eyes..
what’s that “options” variable doing there?
Where does it come from?
It’s never been introduced, it’s undefined, and i assumed it would be passed on as undefined, not having an effect on further execution.
The JavaScript distinction matters: reading an undeclared identifier such as options throws a ReferenceError before the function is called. A declared variable whose value is undefined is different. Omitting the options argument, or passing {}, uses Materialize’s defaults.
We change the code like following:
import { later } from ‘@ember/runloop’;
later(()=>{
var elems = document.querySelectorAll(‘.parallax’);
window.M.Parallax.init(elems);});
Passing no options, alternatively, you may pass an empty hash like so “{}” as second parameter.
Bam, fixed. Parallax’es going for you.
Corrected lifecycle example, 15 October 2026: for a classic Ember component whose child elements include the parallax containers:
import Component from '@ember/component';
export default Component.extend({
didInsertElement() {
this._super(...arguments);
// Requires Materialize JavaScript to be loaded as window.M.
this.parallaxInstances = window.M.Parallax.init(
this.element.querySelectorAll('.parallax')
);
},
willDestroyElement() {
(this.parallaxInstances || []).forEach(instance => instance.destroy());
this._super(...arguments);
}
});Sources: Ember 3.28 component lifecycle and Materialize’s parallax API.
ENJOY!
Originally published on blog.yavuz.support: https://blog.yavuz.support/how-to-materialize-css-parallax.
