Vuetify: 1.0.4
Vue: 2.5.13
Browsers: Chrome 63.0.3239.132
OS: Windows 7
Cards should be rendered side by side (row layout).
When hitting F5, cards are rendering one below the other (column layout) - that is the bug.
When resize the window, cards are rendering as expected (row layout).
When webpack compiles with the page previously opened, cards are rendering as expected (row layout).
It works when using a v-toolbar.
I have been unable to reproduce this error.
Vuetify: 1.0.5
Vue: 2.5.13
Browsers: Chrome 64.0.3282.186
OS: Windows 7
https://github.com/peluprvi/vuetify-issue-3436
Use a computed prop that conditionally changes after nextTick on created hook:
<script>
export default {
props: {
xsOnly: {
type: Boolean,
default: false
}
},
data: () => ({
reloaded: false
}),
computed: {
isXsOnly () {
return this.reloaded ? this.xsOnly || this.$vuetify.breakpoint.xsOnly : this.xsOnly
}
},
created () {
this.$nextTick(function () {
this.reloaded = true
})
}
}
</script>
As I said in discord, this appears to be vuejs/vue#7063 but with classes this time. Try adding a ref to one of those v-layouts and see what happens.
@peluprvi I would consider that bad advice, as it relies on timing. A better solution would be to use the mounted
hook instead:
data: () => ({
isHydrated: false
})
computed: {
breakpoint () { // just an example, could be one specific value if that's all you need
return this.isHydrated
? this.$vuetify.breakpoint
: // "empty" $breakpoint object with initial values
}
}
mounted () {
this.isHydrated = true
}
I've opened a new issue vuejs/vue#7787, follow that for updates.
Based on the response above I've made a simple nuxt plugin so that we don't have to use mounted hooks on every component that needs to use vuetify breakpoints
import Vue from 'vue'
Vue.prototype.$breakpoint = new Vue({
data () {
return {
isMounted: false,
default: {
xs: true,
xsOnly: true,
xsAndUp: false,
sm: true,
smOnly: true,
smAndDown: true,
smAndUp: false,
md: false,
mdOnly: false,
mdAndDown: false,
mdAndUp: false,
lg: false,
lgOnly: false,
lgAndDown: false,
lgAndUp: false,
xl: false,
xlOnly: false,
xlAndDown: false
}
}
},
methods: {
is (breakpoint) {
return this.isMounted ? this.$vuetify.breakpoint[breakpoint] : this.$data.default[breakpoint]
}
}
})
export default async function ({ app }) {
if (!app.mixins) {
app.mixins = []
}
app.mixins.push({
mounted () {
this.$breakpoint.$data.isMounted = true
}
})
}
This did not make the cut for v1.3 and is being refactored for v2.0
None of the suggested solutions worked for me (tried them all)
This is a bit of a hack and not for everyone, but I worked around the issue by triggering a breakpoint recalc in mounted:
mounted() {
this.$vuetify.clientHeight--
this.$vuetify.clientHeight++
}
If you dont mind there being a minor difference in the actual value, this works also:
mounted() {
this.$vuetify.clientHeight -= 0.1
}
Added a computed function to @kovsky0 's nuxt-plugin so the call-syntax is a bit prettier:
import Vue from 'vue'
Vue.prototype.$breakpoint = new Vue({
data() {
return {
isMounted: false,
default: {
xs: true,
xsOnly: true,
xsAndUp: true,
sm: false,
smOnly: true,
smAndDown: true,
smAndUp: false,
md: false,
mdOnly: false,
mdAndDown: true,
mdAndUp: false,
lg: false,
lgOnly: false,
lgAndDown: true,
lgAndUp: false,
xl: false,
xlOnly: false,
xlAndDown: true,
},
}
},
computed: {
is() {
return Object.keys(this.$vuetify.breakpoint).reduce((breakpoints, dim) => {
breakpoints[dim] = this.breakpointWithDefault(dim)
return breakpoints
}, {})
},
},
methods: {
breakpointWithDefault(breakpoint) {
return this.isMounted ? this.$vuetify.breakpoint[breakpoint] : this.$data.default[breakpoint]
},
},
})
export default async function ({ app }) {
if (!app.mixins) {
app.mixins = []
}
app.mixins.push({
mounted () {
this.$breakpoint.$data.isMounted = true
}
})
}
Then you can call it like $breakpoint.is.smAndDown
instead of $breakpoint.is('smAndDown')
Is that still required or fixed on some version ?
Is that still required or fixed on some version ?
yeah! I have same problem at [email protected]
There are similar issues with Vuetify when it comes to server side rendering (Nuxt.js)
@begueradj All right for Off-topic, but where is the issue tracked so we can subscribe to ?
Unfortunately this is still present in the upcoming v2.0 release. As I see some workarounds above, if anyone would like to collaborate in getting a resolution within the framework it would be greatly appreciated. For now I will be moving this from the v2.0 release.
Based on the response above I've made a simple nuxt plugin so that we don't have to use mounted hooks on every component that needs to use vuetify breakpoints
import Vue from 'vue' Vue.prototype.$breakpoint = new Vue({ data () { return { isMounted: false, default: { xs: true, xsOnly: true, xsAndUp: false, sm: true, smOnly: true, smAndDown: true, smAndUp: false, md: false, mdOnly: false, mdAndDown: false, mdAndUp: false, lg: false, lgOnly: false, lgAndDown: false, lgAndUp: false, xl: false, xlOnly: false, xlAndDown: false } } }, methods: { is (breakpoint) { return this.isMounted ? this.$vuetify.breakpoint[breakpoint] : this.$data.default[breakpoint] } } }) export default async function ({ app }) { if (!app.mixins) { app.mixins = [] } app.mixins.push({ mounted () { this.$breakpoint.$data.isMounted = true } }) }
No longer seems to work in veutify 2.0 :(
I've tried every solution listed above and it seems not to work for me.
If you use component like card everything works well but once you use toolbar, the errors come up even when the code is directly from the documentation
Hello everyone.
I have modified plugin code, shown above, and now it is working in vuetify 2.0 and nuxt. Hope that helps someone:
import Vue from 'vue'
Vue.prototype.$breakpoint = new Vue({
data() {
return {
mountedBreakpoints: {},
default: {
xs: true,
xsOnly: true,
xsAndUp: true,
sm: false,
smOnly: true,
smAndDown: true,
smAndUp: false,
md: false,
mdOnly: false,
mdAndDown: true,
mdAndUp: false,
lg: false,
lgOnly: false,
lgAndDown: true,
lgAndUp: false,
xl: false,
xlOnly: false,
xlAndDown: true
}
}
},
computed: {
is() {
return Object.keys(this.$vuetify.default).reduce((breakpoints, dim) => {
breakpoints[dim] = this.breakpointWithDefault(dim)
return breakpoints
}, {})
}
},
methods: {
breakpointWithDefault(breakpoint) {
return Object.keys(this.$data.mountedBreakpoints).length > 0 ? this.$data.mountedBreakpoints[breakpoint] : this.$data.default[breakpoint]
}
}
})
export default async function ({ app }) {
if (!app.mixins) {
app.mixins = []
}
app.mixins.push({
mounted() {
this.$breakpoint.$data.mountedBreakpoints = this.$vuetify.breakpoint
}
})
}
@pantuchy this doesn't work, could you share a gist of your nuxt config and how you are using this ?
Any progress or workaround for this ?
It's getting really hard to make stuff work right when you need to change the viewport for nuxt to realize it's in phone
^
This happens on a real phone as well.
This is what I have come up with loosely based on the comment by pantunchy: https://gist.github.com/douira/6d3f99fa4546adee470637467931ed19
Since this creates a global watcher for every vuetify breakpoint this is probably not the most elegant solution. I'm also not sure if this is ok performance-wise but I can't really imagine something bad happening from looping through a hand full of properties.
This is getting pushed back from v1.2.0 (mid 2018!) to v3.0.0. I think this is important, as everyone developing nuxt with vuetify will face this issue, breaking hydration completely.
@pantuchy 's solution works really well. I think it should be included by default in the create-nuxt-app when choosing vuetify. Also, it should be included in the docs.
Do you think it would be a good idea to submit this as a PR to create-nuxt-app? Or is another solution under development?
The breakpoints xsAndUp
and xlAndDown
don't exist in Vuetify and I've removed them from my updated version of the plugin. See this Vuetify issue about those two breakpoints: https://github.com/vuetifyjs/vuetify/issues/6019
I had some difficulties with the other version of the plugin so I made this one. I don't know which one is preferable for performance and architecture quality.
Place this file in plugins/breakpoint.js
. Register it with Nuxt.js in nuxt.config.js
:
export default {
plugins: ["~/plugins/breakpoint"]
}
and then you can use $breakpoint
in your components with an expression like this.$breakpoint.smAndUp
.
See more info: https://gist.github.com/douira/6d3f99fa4546adee470637467931ed19
import Vue from "vue"
//the properties of breakpoint that we want to mirror
const defaults = {
xs: true,
xsOnly: true,
sm: false,
smOnly: true,
smAndDown: true,
smAndUp: false,
md: false,
mdOnly: false,
mdAndDown: true,
mdAndUp: false,
lg: false,
lgOnly: false,
lgAndDown: true,
lgAndUp: false,
xl: false,
xlOnly: false
}
//create a property on the prototype of all instances that holds the breakpoint state
Vue.prototype.$breakpoint = new Vue({
data: () => ({ ...defaults })
})
export default async function({ app }) {
//init mixins and the watchers if they don't exist yet
app.mixins = app.mixins || []
app.watch = app.watch || {}
//create a watcher for each breakpoint
for (const prop in defaults) {
//the watcher sets the breakpoint prop to cause an update
app.watch[`$vuetify.breakpoint.${prop}`] = function(value) {
//update our mirrored value properly
this.$breakpoint[prop] = value
}
}
//add a mixin that does the client prop setting
app.mixins.push({
//here is the magic, if we set the state with the correct value on client init it works
mounted() {
//for all props that we are processing
for (const prop in defaults) {
//set the initial value from vuetify
this.$breakpoint[prop] = this.$vuetify.breakpoint[prop]
}
}
})
}
Sorry @douira, your solution don't work 馃槩 If I change the viewport the app crashes with the following error:
TypeError: Cannot read property '$breakpoint' of undefined
at Vue.app.watch.<computed> (breakpoint.js?7a54:92)
at Watcher.run (vue.runtime.esm.js?2b0e:4568)
at flushSchedulerQueue (vue.runtime.esm.js?2b0e:4310)
at Array.eval (vue.runtime.esm.js?2b0e:1980)
at flushCallbacks (vue.runtime.esm.js?2b0e:1906)
Tried the solution provided by @pantuchy and this works. But it's just a workaround.
Both are workarounds and work differently. Neither is a solution since they both do a similar thing; creating a reactive breakpoint object that also works in SSR even though Vuetify currently has none.
I can't figure out what went wrong in your project since this stacktrace doesn't really say anything. Are you sure you're not using .is
? You need to use it with this.$breakpoint.smAndUp
. If you show me more of the code using $breakpoint
, I might be able to troubleshoot. If the other version works for you that's just fine as well though.
If someone is interested in a workaround for a vue-ts class style component.
It inspired by the solution from @KaelWD and works like a charm.
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
import { Breakpoint } from 'vuetify/types/services/breakpoint'
@Component({
})
export default class ExampleComponent extends Vue {
breakpoint: Partial<Breakpoint> = {}
mounted () {
// assign vuetify breakpoints after mount, because there is no screensize available in ssr
this.breakpoint = this.$vuetify.breakpoint
}
}
</script>
Most helpful comment
As I said in discord, this appears to be vuejs/vue#7063 but with classes this time. Try adding a ref to one of those v-layouts and see what happens.
@peluprvi I would consider that bad advice, as it relies on timing. A better solution would be to use the
mounted
hook instead: