How to navigate to a route in Framework7 + Vue app? - javascript

How to navigate to a route in Framework7 & VueJs app.
I want to show a slpash screen and navigate to next page after two seconds. Code is pasted below.
<template>
...
</template>
<script>
export default {
name: "splash",
mounted: function() {
this.$router.load({url: '/about/'}); // error
},
data: function () {
return {
msg : "hello"
}
}
}
</script>
Note: This is app component(Main.vue).

Finally this worked for me.
this.$f7.mainView.router.load({url: "/user-settings"})
From Docs
Please note, that $route and $router component properties are only available inside of custom page components (and their child components) that you load according to routes. In parent components (like in View, or where you init your Vue app instance) they are not accessible as your app may have few routers (Views) at a time. So in this case use access to initialized View Instance, e.g. $f7.views.main.router or $f7.mainView.router

Related

VueJS component's Created()/Mounted() event is getting called while leaving the component

I have an AngularJS application where I'm using few components of Vue (version 2).
The Navigation bar of the app is in AngularJS.
When I switch between different navigation options (Home/Support), I'm loading the related Vue components.
VueJS project is built using npm run buid-lib and linked in angularJS app (npm link). Library name is myVueApp.
Using ngVue library to integrate Vue with AngularJS.
Code to load Vue Components in AngularJS app (as plugin):
(function() {
'use strict';
if (typeof myVueApp !== 'undefined') {
var VueContainer = myVueApp.components.VueContainer,
plugins = myVueApp.plugins;
}
angular
.module('my.vue.config', ['ngVue', 'ngVue.plugins'])
.config(function($ngVueProvider) {
$ngVueProvider.setRootVueInstanceProps(plugins);
})
// Add Vue components here
.value('VueContainer', VueContainer);
})();
In HTML page, I'm loading the component like below example:
Home.Html (In AngularJS)
<div>
<vue-component name="VueContainer"></vue-component>
</div>
Routing of the Vue Components in Angular Controller:
var ngModule = angular.module('home.content', ['ui.router']);
ngModule.config(function ($stateProvider) {
$stateProvider
.state('home.content', {
url: '?home&t',
controller: 'HomeCtrl as HomeCtrl ',
templateUrl: '/views/home.html',
resolve: {
},
onEnter: function(){
}
});
When I switch between Vue Components, the Created/Mounted event of the each Vue component (callee and called) is getting called.
Example Vue Components:
HomeComponent.Vue
async created() { //This is called every time it is switched to other component
await this.getHomeData();
this.loading = false;
}
SupportComponent.Vue
created() { //This is called every time it is switched to other component
this.$store.dispatch('getAllSupportProp');
this.loadDetails();
}
In angular app, when I swtich from HomeComponent.Vue to SupportComponent.Vue or vice-versa, created/mounted events of both the components are getting called while it should only call the target component's created event.
When I run the Vue app alone (not with AngularJS), the switching between components doesn't have this problem (Callee component doesn't get called).

Vue component inside legacy php/jquery project

I've got this big legacy web app based on Codeigniter and jQuery.
The plan is to phase out jQuery and start using Vuejs instead. We are replacing certain parts of the website step by step.
I have just installed Nuxtjs and got the file structure the way i like it inside the legacy project.
Now to the question. How can i access a Vue component from one of my legacy javascript files?
App.vue
<template>
<div id="app">
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
</div>
</template>
<script lang="ts">
import Vue from "vue";
import HelloWorld from "./components/HelloWorld.vue";
export default Vue.extend({
name: "App",
components: {
HelloWorld
}
});
</script>
main.ts
import Vue from "vue";
import App from "./App.vue";
import store from "./store";
Vue.config.productionTip = false;
new Vue({
store,
render: h => h(App)
}).$mount("#app");
I want to display my App.vue inside an ordinary php/html view.
I am doing something similar right now, the project was originally written using Thymeleaf and jQuery and now we are switching to Vue.
You can communicate between vue components and non-vue components in a few ways, none of them are "pretty".
Communication
Classic JavaScript events
Pretty straightforward
// legacy code
document.dispatchEvent(new CustomEvent('legacy-vue.something-happened', { detail: payload }))
// vue component
created () {
document.addEventListener('legacy-vue.something-happened', this.onSomethingHappened)
},
destroyed () { // don't forget to remove the listener!
document.removeEventListener('legacy-vue.something-happened', this.onSomethingHappened)
}
Exposing EventHub
Similar to the previous one, but you are using vue events instead. This is what i would recommend, because it's the Vue way of handling events and your goal is to vuetify your app.
// initialization
const hub = new Vue()
Vue.prototype.$eventHub = hub
window.$vueEventHub = hub
// legacy code
$vueEventHub.$emit('something-happened', payload)
// vue component
created () {
this.$eventHub.$on('something-happened', this.onSomethingHappened)
},
destroyed () {
this.$eventHub.$off('something-happened', this.onSomethingHappened)
}
Exposing whole components
The most flexible way, but it's hard to see what's going on where. Event based approaches the lesser evil in my opinion (it's easy to track events).
// vue component
created () {
window.vueTableComponent = this
}
// legacy component
vueTableComponent.fetchNextPage()
vueTableComponent.registerOnPageFetchedCallback(callback);
Summary
No matter which approach you pick, i recommend doing something like this:
Let's say that you have TableComponent. TableComponent has few props like apiUrl, emits row-clicked event, etc. It would be best to design the component without thinking about your legacy code at all, and then create it's legacy wrapper because at one point it will be used both with vue-only screens and with mixed-screens (with both legacy components and vue components). An example:
LegacyTableComponentWrapper.vue
<template>
<table-component
:api-path="apiPath"
#row-clicked="onRowClicked"
ref="table-component"
/>
</template>
export default {
data: () => ({
apiPath: null
}),
methods: {
onRowClicked (row) {
this.$eventHub.$emit('table-row-clicked', row) // notify legacy code
},
onApiPathDefined (payload) {
this.apiPath = payload
}
},
mounted () {
// legacy code might require the TableComponent to act differently
// and if you don't want the TableComponent to know whenever it's legacy or not
// you can always override one or more of it's methods.
this.$refs['table-component'] = this.overriddenImplementationOfXYZ
},
created () {
this.$eventHub.$on('define-api-path', this.onApiPathDefined)
},
destroyed () {
this.$eventHub.$off('define-api-path', this.onApiPathDefined)
}
}
It's sure more work at first, but will save you a headache later, when you will be working on your first view which is fully in vue and all that legacy communication stuff is in the way.

How to access routing parameters in Vue.js - Nuxt - TypeScript application?

I'm building a website that is based on Nuxt TypeScript Starter template. I've created a dynamically routed page _id.vue inside of my pages folder and I want to have access to that id property inside of my TS class.
I can access it in my template by writing {{$route.params.id}} but when I try to reference $route inside of the class I get an error:
error TS2304: Cannot find name '$route'.
As a simple solution, try importing route from vue-router, like this:
<script lang="ts">
import Component from "vue-class-component"
import { Route } from "vue-router"
#Component({})
export default class RoutingExample extends Vue {
created() {
console.log(this.$route) // this should not throw TS errors now
}
}
</script>
Other solutions I think would require you to augment the Vue module, something similar to what you'd find here in the Vue docs.
More Vue + TypeScript examples can be found in this repo: https://github.com/jsonberry/vue-typescript-examples
better and the right solution for nuxtjs project to find current page URL or param just use
{{ $nuxt.$route.name }}
I was able to access route.params via fetch function, taking params from the context object that is passed to this function by default:
<script lang="ts">
import Component from "nuxt-class-component"
#Component({})
export default class RoutingExample extends Vue {
fetch ({ store, params }) {
console.log("params:", params.id);
...
}
}
</script>
but the caveat is that params would only be available in that fetch hook, not in other hooks such as created or mounted. So Jason answer is also valid

How to define property with a component?

I currently have three steps in a form that I want to show sequentially, so I created three components - one for each step of the process.
My app.js file:
import LocationList from './components/LocationList.vue';
import ChooseTime from './components/ChooseTime.vue';
import ChooseMethod from './components/ChooseMethod.vue';
Vue.component('location-list', LocationList);
Vue.component('choose-time', ChooseTime);
Vue.component('choose-method', ChooseMethod);
let store = {
isVisible: {
steps: {
one: true,
two: false,
three: false,
}
}
};
new Vue({
el: '#app-order',
data: store,
router
});
Now, when my one and only route is called,
import VueRouter from 'vue-router';
let routes = [
{
path: '/order',
component: require('./views/Order.vue')
}
];
export default new VueRouter({
routes
});
all these components are being loaded properly. The issue is that when I try to v-show them one at a time:
Order.vue:
<template>
// ...
<location-list v-show="isVisible.steps.one"></location-list>
<choose-time v-show="isVisible.steps.two"></choose-time>
<choose-method v-show="isVisible.steps.three"></choose-method>
// ...
</template>
<script>
</script>
<style>
</style>
The error message I receive is:
[Vue warn]: Property or method "isVisible" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
But when I check within Vue's browser extension, isVisible is defined within the root element?
As you can see it is in the root-element, but not inside the Order view though.
Thanks for any help!
In Vue, child components do not have direct access to data defined in their parents. You have to pass the data down.
I think you would probably save yourself a little trouble if you just defined isVisible in Order.vue. However, if you want to leave it where it is, you need to pass it into the component.
One easy way to do that is to define isVisble as a property of Order.vue and then pass it through your router-view.
<router-view :is-visible="isVisible"></router-view>
There are other ways of passing props to routes that are defined in the router documentation.
The reason I say you would save your self some trouble defining isVisible in Order.vue is because whenever you want to change the values of your steps, you will need to do it at the root as you currently have it defined.

Why is my Component not calling its init method?

I have a UIComponent which has a dependency of a faceless Component.
Main component metadata:
jQuery.sap.declare("MYAPP.Component");
sap.ui.core.UIComponent.extend("MYAPP.Component", {
metadata: {
dependencies: {
libs: [],
components: [
"MYAPP.Component2"
]
}, etc
The app indicates it has reached the faceless component, since if I make some deliberate syntax errors I do get the error messages when loading the webpage. I can also get a console.log("test") to print out from outside the sap.ui.core.Component.extend() code.
jQuery.sap.declare("Component2.Component");
console.log("outside test"); //this prints
sap.ui.core.Component.extend("Component2.Component", {
metadata: {
},
init: function(){
sap.ui.core.Component.prototype.init.apply(this, arguments);
console.log("component2 init test"); //this doesn't print
}
});
Perhaps there's an issue with my declarations of resources?
Some of index.html:
<script id='sap-ui-bootstrap' type='text/javascript'
src='resources/sap-ui-core.js'
data-sap-ui-theme='sap_bluecrystal'
data-sap-ui-libs='sap.m, sap.me'
data-sap-ui-xx-bindingSyntax="complex"
data-sap-ui-xx-supportedLanguages="en"
data-sap-ui-resourceroots='{"MYAPP":"./"}'></script>
<script>
sap.ui.localResources("view");
sap.ui.localResources("utils");
sap.ui.localResources("control");
sap.ui.localResources("Component2");
My folder structure:
MYAPP
/Component2 //faceless component folder
Component.js
/view //views and controllers folder
Component.js //main component
index.html
The answer I've found with some help from a user at SCN (here) is that the parent component's metadata will call a function to load the new component without instantiating it. So you must explicitly create the component as well.
I have added a simple sap.ui.component in the init() function of my parent component.
sap.ui.component({ name: "MYAPP.Component2" });
Now the new component is loaded and instantiated before the parent component. Hopefully this post will help others using faceless components, as I found little documentation myself when researching this problem.

Categories