I'm using Angular2 routing and I need to subscribe to an event when route is changed. (i.e. user clicked on one of the route links). The important thing is that the event should be when the new view HTML is inserted to DOM.
Are there any events like onNavigating and onNavigated, so I can subscribe to?
I've found a couple of examples on stackoverflow and tried to use them (see constructor below), but that didn't work. Any ideas?
/// <reference path="../../typings/tsd.d.ts" />
import {Component, View} from 'angular2/angular2';
import {RouteConfig, Router, RouterOutlet, RouterLink} from 'angular2/router';
#RouteConfig([...])
#Component({
selector: 'app'
})
#View({
directives: [RouterOutlet, RouterLink],
template: `
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
<header class="mdl-layout__header">
<div class="mdl-layout__header-row">
<span class="mdl-layout-title">Test</span>
<div class="mdl-layout-spacer"></div>
<nav class="mdl-navigation mdl-layout--large-screen-only">
<a class="mdl-navigation__link" [router-link]="['/routelink1']">routelink1</a>
</nav>
</div>
</header>
<main class="mdl-layout__content" style="padding: 20px;">
<router-outlet></router-outlet>
</main>
</div>
`
})
export class App {
constructor(private router: Router){
router.subscribe((val) => function(){...}); //here is I need to process HTML
}
}
I ended up with having base class for my routing components and it contains routerOnNavigate override.
import {OnActivate, ComponentInstruction} from 'angular2/router';
export class BaseView implements OnActivate {
routerOnActivate(next: ComponentInstruction, prev: ComponentInstruction) {
componentHandler.upgradeDom();
}
}
Related
I have app.component which is creating by default and here is a button. When I click it, I want to go to login.component.
Here is my app.module.ts file
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppRoutingModule } from './app-routing/app-routing.module';
import { AppComponent } from './app.component';
import { MatButtonModule } from '#angular/material/button';
import { MainModule } from './main/main.module';
#NgModule({
declarations: [AppComponent],
imports: [BrowserModule, MatButtonModule, MainModule, AppRoutingModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
Here is my app-routing.module.ts code
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { LoginComponent } from '../main/login/login.component';
const routes: Routes = [
{ path: 'main', children: [{ path: 'login', component: LoginComponent }] },
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
Here is how I try to do this - <button mat-raised-button class="btn-default" [routerLink]="['/main/login']">Log in</button>
Here is stackblitz url to check code Stackblitz
My problem is, that link changed to localhost:4200/main/login, but view not changed.
How I can solve this?
This is a CSS issue. split left and spit right do not give the login component inside any space. Instead, have your main page (main-page) (the page with the login and sign up button) as its own component, and have split right only having the router outlet.
app.component.html
<div class="split left">
<div class="centered">
<h1>Learn what you want.</h1>
<h1>Teach what you love.</h1>
</div>
</div>
<div class="split right">
<router-outlet></router-outlet>
</div>
main-page.component.html
<div class="centered">
<div>
<button mat-raised-button class="btn-default" [routerLink]="['/main/login']">Log in</button>
</div>
<div style="margin-top: 20px">
<button mat-raised-button class="btn-default-transparent">Sign up</button>
</div>
</div>
I created a bug-fixed version here for you: Stackblitz
Your problem was that it loaded but behind the app.component.html template.
You created a main module for LoginComponent. When You have more than one module the best practice is to use Lazy Loading which I created for you on my demo. In addition, it's better that app-component, mean main app just have <router-outlet></router-outlet> and content loads from other component.
So the problem was not in CSS
Problem was that I need to have all components to be separate and have <router-outlet></router-outlet> only in app.component.ts file.
I'have multiple auth laravel dashboard. When i login the default page redirect me to the client dashboard blade. When i write something in client blade.It does not show anything.I am using vuejs routers. Everything is working perfect. I tried to call component in that blade but it's still showing blank .I want to redirect to dashboard component.
Controller:
I tried it with the return url('url here') but still not working for me.
public function index()
{
return view('client');
}
Client Blade:
#extends('layouts.master')
#section('content')
<template>
<div class="container-fluid">
<client_details></client_details>
</div>
</template>
<script>
import clientdetails_header from "./clientdetails_header.vue";
export default {
data() {
return {
}
},
components: {
'client_details': clientdetails_header
},
mounted() {
console.log('Component mounted.')
}
}
</script>
#endsection
Master Blade:
<ul>
<li>
<router-link to="/clientdashboard" title="dashboard">
<span class="nav-link-text"><iclass="fal fa-user"></i>DashBoard</span>
</router-link>
</li>
</ul>
<div class="page-wrapper" id="app">
<div class="page-content">
<router-view>
</router-view>
</div>
</div>
App.js
let routes = [
{path: '/clientdashboard', component: require('./components/clientdashboard.vue').default},
]
const app = new Vue({
el: '#app',
router,
});
const router = new VueRouter({
mode: "history",
routes
})
ClientHeader:
<template>
<div class="row">
<div class="col-xl-12">
<!-- Collapse -->
<div id="panel-6" class="panel">
<div class="panel-hdr">
<h2>
Client Details
</h2>
</div>
<div class="panel-container show">
<div class="panel-content">
<div class="row">
<div class="col-md-2">
<span><b>Company name:</b></span> <br>
<span><b>Company ABN:</b></span> <br>
<span><b>Company address:</b></span> <br>
<span><b>Company phone:</b></span> <br>
<span><b>Company email:</b></span> <br>
</div>
<div class="col-md-10">
<ul style="list-style: none;" class="list-group list-group-flush">
<li style="text-decoration: none" v-for="todo in clientData">{{todo}}</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
user_id: this.$userId,
clientData: {}
}
},
methods: {
getClientDetails() {
axios.post(this.$path + 'api/getClientDetails', null,
{
params: {
'client_id': this.user_id,
}
})
.then(data => (
this.clientData = data.data));
}
},
mounted() {
this.getClientDetails();
console.log('Component mounted.')
}
}
</script>
I don't think it's a good idea trying to put Vue code directly inside blade.
I would suggest you create a Client.vue and put your code in it instead. Register it in your routes in app.js.
...
{path: '/client', component: require('./components/Client.vue')},
Then you can use the component in your Client blade.
<client></client>
I believe that would be a first step towards resolving this issue.
Load your app.js in <head> section of your blade.php
<script src="{{ asset('js/app.js') }}" async></script>\
Also create a div with id app there.
<body>
<div id="app"></div>
</body>
Create App.vue
<template>
<div>
<router-view />
</div>
</template>
<style scoped lang="scss">
</style>
Go to resources/js/app.js file, you will see laravel already put code to instantiate vue in there. Register your route etc.
But for me, I create a new folder resources/js/vue, put all vue related files (components, routes, filters, vuex, mixins, directives) there, create index.js and moved the code to initiate vue inside index.js.
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
import components from './components'
import directives from './directives'
import mixins from './mixins'
import filters from './filters'
Vue.use(router)
Vue.use(store)
Vue.use(components)
Vue.use(directives)
Vue.use(mixins)
Vue.use(filters)
new Vue({ router, store, render: h => h(App) }).$mount('#app')
export default {}
resources/js/app.js
require('./vue')
// I also initiate service-worker, firebase, and other non vue related
// javascripts in this file
I have a project in angular 7
I have router links with <a> tag, and I have nested <a> tags that both have routerLink property,
the issue I am facing is , the inner <a> route doesn't work
<a [routerLink]="[ './comp1']">
Comp1
<a [routerLink]="['./comp2']">
Navigate to comp2 (Nested)
</a>
</a>
this is working if I separate it
<div>
<a [routerLink]="['./comp2']">
Navigate to comp2 (Not Nested)
</a>
</div>
Also I tried the below code and still same
<a [routerLink]="[ './comp1']">
Comp1
<a [routerLink]="['./comp2']" (click)="$event.preventDefault()>
Navigate to comp2 (Nested)
</a>
</a>
changing a tags to span also doesn't solve the issue
<span [routerLink]="[ './comp1']" >
Comp1
<span [routerLink]="['./comp2']" (click)="$event.preventDefault()">
Navigate to comp2 (Nested)
</span>
</span>
Here is the https://stackblitz.com/edit/angular-nested-router for it
In your stackblitz add the following function to your component class. It receives the event as parameter and calls the stopPropagation function on it.
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
stop(event: Event) {
event.stopPropagation();
}
}
In your template do
<router-outlet></router-outlet>
<a routerLink="/comp1">
Comp1
<a routerLink="/comp2" (click)="stop($event)">
Navigate to comp2 (Nested)
</a>
</a>
See my stackblitz fork.
I am using Larvel (latest version) and I am attempting to make a SPA using vuejs. I followed a SPA tutorial in the laracast episodes about vue js. However, i am having a little bit of trouble. I think im doing something wrong in the routes.js file because in the tutorial it says to make the component be require(./views/home) but the require function is not being
resolved.
The problem is that on the page the router-link tag is not being compiled to an anchor tag
Boostrap.js
import Vue from 'vue';
import axios from 'axios';
import VueRouter from 'vue-router';
window.Vue = Vue;
Vue.use(VueRouter);
window.axios = axios;
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
Router.js
import VueRouter from 'vue-router';
let routes = [
{
path:'/',
component: require('./views/home')
}];
export default new VueRouter({
routes
});
App.js
import './bootstrap';
import router from './routes'
new Vue({
el: '#app',
router
});
home.vue
<template>
<section class="hero is-dark">
<div class="hero-body">
<div class="container">
<h1 class="title">
Primary title
</h1>
<h2 class="subtitle">
Primary subtitle
</h2>
</div>
</div>
</section>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>
nav
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
#include('partials.head')
<title>My App</title>
</head>
<body class="">
<div class="wrapper">
<div class="content-wrapper">
<div id="app">
<router-link to='/'>Home</router-link>
<router-link to='/about'>About</router-link>
</div>
</div>
</div>
#include('partials.footer')
</body>
</html>
Mix
mix.js('resources/assets/js/app.js', 'public/js')
When looking at your bootstrap.js, it seems you are doing Vue.use(‘VueRouter’). When calling the use method, you need to pass it the VueRouter object you imported, and not a string literal.
I just try to follow the example about the use of slot on the Vue official site. But it failed, I have made the code very short
parent component
<template>
<subMenuTemp>
<div class="text" >
parent content
</div>
</subMenuTemp>
</template>
<script>
import subMenuTemp from 'src/test/testChildren.vue'
export default {
data() {
},
components: {
subMenuTemp
}
}
</script>
children component another .vue file
<template>
<div class="content">
<slot>
old content
</slot>
</div>
</template>
<script>
export default {
}
</script>
although the code is very short, I still cannot find where is my fault
Make sure to include the two components in your main.js or some .js file that imports Vue. It should look like this:
import Vue from 'vue'
import App from './App'
import subMenuTemp from './test/testChildren.vue'
new Vue({
el: '#app',
template: '<App/>',
components: { App, subMenuTemp }
})
You don't need to register all components in the main file as pointed in other answers.
You just need to import the child component into the parent component just as you do.
See a here: https://codesandbox.io/s/vue-template-oy15j?fontsize=14
// App.vue
<template>
<div id="app">
<parent-component message="Hello Vue !"/>
</div>
</template>
<script>
import ParentComponent from "./components/ParentComponent";
export default {
name: "App",
components: { ParentComponent }
};
</script>
// ParentComponent.vue
<template>
<child-component>
<div class="test-parent">{{ message }}</div>
</child-component>
</template>
<script>
import ChildComponent from "./ChildComponent";
export default {
name: "ParentComponent",
components: { ChildComponent },
props: {
message: String
}
};
</script>
// ChildComponent.vue
<template>
<div class="test-child">
<slot>default content</slot>
</div>
</template>
<script>
export default {
name: "ChildComponent"
};
</script>
<!-- Result -->
<div id="app">
<div class="test-child">
<div class="test-parent">Hello Vue !</div>
</div>
</div>