nativescript-vue / nativescript-vue-navigator

A simple router for NativeScript-Vue, built on top of $navigateTo to simplify routing from within components
MIT License
98 stars 10 forks source link

$navigator.path not updated correctly if using class style Vue components #31

Closed superalex closed 4 years ago

superalex commented 4 years ago

I have a sample where I'm using your plugin to navigate to two different components and show the path in the $navigator.path and it works perfectly:

app.js

import Vue from 'nativescript-vue';

import App from './components/App';

import Navigator from 'nativescript-vue-navigator'
import { routes } from './routes'
Vue.use(Navigator, { routes })

new Vue({
    render: h => h(App),
}).$start();

routes/index.js

import C1 from '~/components/c1'
import C2 from '~/components/c2'

export const routes = {
    '/route-1': {
        component: C1,
    },
    '/route-2': {
        component: C2,
    }
}

compontents/App.vue

<template>
    <GridLayout class="App" rows="*, auto">
        <ContentView row="0">
            <Navigator defaultRoute="/route-1" />
        </ContentView>

        <nav row="1" />
    </GridLayout>
</template>

<script>
    import nav from "./nav";
    export default {
        components: {
            nav
        },
        data() {
            return {};
        }
    };
</script>

components/c1.vue

<template>
    <Page class="page">
        <StackLayout>
            <Label text="Component 1" />
        </StackLayout>
    </Page>
</template>

<script>
    export default {};
</script>

components/c2.vue

<template>
    <Page class="page">
        <StackLayout>
            <Label text="Component 2" />
        </StackLayout>
    </Page>
</template>

<script>
    export default {};
</script>

If I use class Style Vue components with in the components:

components/c2.vue

<template>
    <Page class="page">
        <StackLayout>
            <Label text="Component 2" />
        </StackLayout>
    </Page>
</template>

<script>
    @Component
    export default class C2 extends Vue { };
</script>

Then $navigator.path isn't correctly updated and keeps the initial value.

rigor789 commented 4 years ago

I have no idea what's causing that with class components.

Can you create a watcher and watch $navigator.path see if changes get triggered? $navigator itself is just a Vue instance, nothing magic going on there.

superalex commented 4 years ago

I tried the watcher but nothing get triggered.

I added some console logs and i found that if I do:

  Vue.mixin({
    mounted() {
      console.log("Mounted", this.$options.__path)
      // attach the current path if set to the root element
      if (this.$options.__path) {
        this.$el.setAttribute('__path', this.$options.__path)
      }
    },
  })

And navigate to a "normal" component the console shows:

JS: 'Mounted' undefined JS: 'Mounted' '/wishlist' JS: 'Mounted' undefined

But with a class style component just:

JS: 'Mounted' undefined JS: 'Mounted' undefined JS: 'Mounted' undefined

It seems class style component doesn't receive properly the $options.__path

rigor789 commented 4 years ago

Can you share the compiled source of a class component? (it should be in platforms folder somewhere in a bundle.js if I remember correctly). It's usually a long transpiled file with all your code - but the component should be there somewhere. Might give us a clue why $options.__path is not set.

superalex commented 4 years ago

Sure!

The compiled source for:

<script lang='ts'>
import { Component, Vue } from "vue-property-decorator";
@Component
export default class C1 extends Vue {
}
</script>

Should be:

var C1 = /** @class */ (function (_super) {
    Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(C1, _super);
    function C1() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    C1 = Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__decorate"])([
        vue_property_decorator__WEBPACK_IMPORTED_MODULE_1__["Component"]
    ], C1);
    return C1;
}(vue_property_decorator__WEBPACK_IMPORTED_MODULE_1__["Vue"]));
/* harmony default export */ __webpack_exports__["default"] = (C1);
rigor789 commented 4 years ago

Yeah, that's way different from regular js components...

If you edit the source of the navigator, specifically this line: https://github.com/nativescript-vue/nativescript-vue-navigator/blob/b19adc2d73aaebdcbfc0e8e927b8e59c4b2c4eca/index.js#L13

If you add

if(routes[path].component.options) {
  routes[path].component.options.__path = path
}

Does that make a difference?

(ref: https://github.com/vuejs/vue-class-component/issues/337)

superalex commented 4 years ago

¡Yes!, with that change the Watch works and $navigator.path is correctly updated :)

Thank you veru much! :man_dancing:

rigor789 commented 4 years ago

Great! Mind opening a PR with the change?

Perhaps add a comment above the if block explaining why this is needed, something like

// this is required to attach the path to vue-class-components. see #31
if(routes[path].component.options) {
  routes[path].component.options.__path = path
}
superalex commented 4 years ago

Sure! Thank you very much!

El jue., 26 mar. 2020 22:10, Igor Randjelovic notifications@github.com escribió:

Great! Mind opening a PR with the change?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/nativescript-vue/nativescript-vue-navigator/issues/31#issuecomment-604688451, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAMBU4PWMRCCALRNQLXENWDRJPAEXANCNFSM4LULJPKA .

github-actions[bot] commented 4 years ago

:tada: This issue has been resolved in version 1.1.1 :tada:

The release is available on:

Your semantic-release bot :package::rocket: