I have a navbar with the router links like in the Aurelia skeleton, but I want to also have parameterized links inside the router-view that change the router-view. Is this possible? If so, how do I access the router which is on App.ts? Any help is appreciated, thanks.
You just have to inject the router in your view-model. Like this:
import { autoinject } from 'aurelia-framework';
import { Router } from 'aurelia-router';
#autoinject
export class MyScreenInRouterView {
constructor(router: Router) {
this.router = router;
}
}
To use it in your view:
<a route-href="route: routeName; params.bind: { id: user.id }">${user.name}</a>
To generate URLs in code:
this.url = this.router.generate('routeName', { id: 123 });
To navigate to a route:
this.router.navigateToRoute('routeName', { id: 123 });
More information at http://aurelia.io/hub.html#/doc/article/aurelia/framework/latest/cheat-sheet/7
Related
i use vue3 with class-component in typescript my class looks like:
import {Options, Vue} from "vue-class-component";
#Options({
props: {
result: Object
}
})
export default class imageResult extends Vue {
currentImage = 0;
getSlides(){
console.log('result',this.$props.result); // not working
console.log('result',this.result); // not working too
}
My question is, how can i access and use the property within my class?
both this.result and this.$props.result throws me an error.
can someone help me?
Thanks in advance
late answer but maybe it helps someone in the future.
works for me with vu3 & typescript
<script lang="ts">
import { Vue, prop } from "vue-class-component";
export class Props {
result = prop<string>({ required: true });
}
export default class Foo extends Vue.with(Props) {
test(): void {
console.log(this.result);
}
}
</script>
My suggestion to you is to follow the documentation on using Typescript with vue using class component: enter link description here
in order to fix your code I think this should work:
import {Vue} from "vue-class-component";
import {Component} from "vue-class-component";
// Define the props by using Vue's canonical way.
const ImageProps = Vue.extend({
props: {
result: Object
}
})
// Use defined props by extending GreetingProps.
#Component
export default class ImageResult extends ImageProps {
get result(): string {
console.log(this.result);
// this.result will be typed
return this.result;
}
}
I am using Vue 3 with Composition API, and I want to use a third-party package (for example #meforma/vue-toaster), and it should be used like this (in Options API):
import Toaster from '#meforma/vue-toaster';
createApp(App).use(Toaster).mount('#app')
and then in the component:
this.$toast.show(`Hey! I'm here`);
this.$toast.success(`Hey! I'm here`);
this.$toast.error(`Hey! I'm here`);
this.$toast.warning(`Hey! I'm here`);
this.$toast.info(`Hey! I'm here`);
But this is not working inside the Composition API's setup() function.
#meforma/vue-toaster installs $toast on the application context, which can be accessed from getCurrentInstance().appContext.globalProperties in setup():
<template>
<button #click="showToast">Show toast</button>
</template>
<script>
import { getCurrentInstance } from 'vue'
export default {
setup() {
const $toast = getCurrentInstance().appContext.globalProperties.$toast
return {
showToast() {
$toast.show(`Hey! I'm here`)
$toast.success(`Hey! I'm here`)
$toast.error(`Hey! I'm here`)
$toast.warning(`Hey! I'm here`)
$toast.info(`Hey! I'm here`)
setTimeout($toast.clear, 3000)
}
}
}
}
</script>
i've the same issue.
So i've found and easy way to do:
I'm using Vite BTW.
my main.js
import { createApp } from 'vue'
import App from './App.vue'
import Toaster from '#meforma/vue-toaster';
let app = createApp(App)
app.use(Toaster, {
position: 'top-right'
}).provide('toast', app.config.globalProperties.$toast)
app.mount('#app')
my component:
import { inject } from 'vue'
export default {
name: 'table-line',
setup(props) {
const toast = inject('toast');
toast.success(`it works !`)
return {toast}
}
}
Hope it could be helpful
The setup function runs one-time before the component is created. It lacks the this context and may not be where you would want to place these anyway. You could try putting it into a method that you can call via a button.
I feel as though similar questions have already been asked, but I have been unable to find my answer.
I'm trying to segregate my application by its features. Ideally each feature would be able to setup its own routing as well and Aurelia's child-router functionality seemed to be the perfect fit, but I'm having trouble getting it to work.
The structure of the application is as such:
app.ts
app.html
/lectures
list.ts
list.html
details.ts
details.html
index.ts
index.html
I can include any of the other files if needed to answer the question, but have tried to keep the question as compact as possible. The app.html and lectures/index.html files both only contain <template><router-outlet></router-outlet></template>.
I have app.ts:
import { Router, RouterConfiguration } from 'aurelia-router';
export class App {
configureRouter(config: RouterConfiguration, router: Router) {
config.options.pushState = true;
config.map([
{
moduleId: './public-site/lectures',
name: 'lectures',
nav: true,
route: ['', 'lectures/:id?'],
title: 'Lectures'
}
]);
}
}
lecture/index.ts
import { Router, RouterConfiguration } from 'aurelia-router';
export class Index {
configureRouter(config: RouterConfiguration, router: Router) {
config.options.pushState = true;
config.map([
{ route: '', moduleId: './list' },
{ route: ':id', moduleId: './details' }
]);
}
}
and then I have lectures/details.ts
import { NavigationInstruction, RouteConfig, RoutableComponentActivate } from 'aurelia-router';
export class LectureDetails implements RoutableComponentActivate {
activate(params: any, routeConfig: RouteConfig, navigationInstruction: NavigationInstruction): Promise<any> {
debugger;
}
}
and lecture\list.html
<template>
<div repeat.for="lecture of lectures" class="grid-body-cell" click.delegate="navigateToLecture(lecture)">
${lecture.title}
</div>
</template>
lecture\list.ts
import { autoinject } from 'aurelia-framework';
import { Router } from 'aurelia-router';
#autoinject()
export class LecturesList {
constructor(private router: Router) {}
navigateToLecture(lecture: {id:number}) {
this.router.navigate(`#/lectures/${lecture.id}`);
}
}
When the app loads, it correctly navigates and displays the list page, but when I click on any of the lectures in the grid, the url updates to /lectures/1, but my debugger statement never gets hit. I can't figure out what I'm doing wrong.
What seems to be happening is that, while the url gets updated, the router is still directing the application to the list component. Is there a way to get the router to honor and pass on the parameter to the child router?
How do I need to update my setup to get the child router to work with the parameter?
Firstly, the router element for displaying routed views is called <router-view> so your views for child routers should be: <template><router-view></router-view></template> - I believe <router-outlet> is what you use in Angular 2+ applications for routing. I am making the assumption here you are already doing that if you're seeing things being rendered.
Secondly, you have config.options.pushState = true defined on your root router configuration and then inside of your navigateToLecture method you are passing in a hash (which is what you would do if you're not using pushState). So Aurelia is removing the hash from the URL (as intended) because you're using pushState and pushState URL's don't need to use the # hack.
Thirdly, I would name your routes (and you'll discover why in a moment). Naming your routes allows you to reference them by name and use either navigateToRoute('routename', {paramsobject}) or route-href (which we discuss below).
So, in lecture/index.ts, put a name property on your routes:
import { Router, RouterConfiguration } from 'aurelia-router';
export class Index {
configureRouter(config: RouterConfiguration, router: Router) {
config.options.pushState = true;
config.map([
{ route: '', name: 'lecture-list', moduleId: './list' },
{ route: ':id', name: 'lecture-detail', moduleId: './details' }
]);
}
}
And lastly, instead of having a click event in your view which is calling router.navigate, you can use the route-href attribute which will allow you to make links work with the router. So, something like the following:
<template>
<div repeat.for="lecture of lectures" class="grid-body-cell">
<a route-href="route: lecture-detail; params.bind: { id: lecture.id }">${lecture.title}</a>
</div>
</template>
Notice how we are referencing our newly named route by its name, lecture-detail? Now Aurelia will come through and parse our link and update the href property to go where it needs too.
Hope that helps.
app.html
<template><router-view></router-view></template>
app.ts
import { Router, RouterConfiguration } from 'aurelia-router';
export class App {
configureRouter(config: RouterConfiguration, router: Router) {
config.pushState = true;
config.map([
{
moduleId: './lectures/index',
name: 'lectures',
nav: true,
route: ['', 'lectures/*id'],
title: 'Lectures'
}
]);
};
}
lectures/index.html
<template><router-view></router-view></template>
lectures/list.html
<template>
<div repeat.for="lecture of lectures" class="grid-body-cell" click.delegate="navigateToLecture(lecture)">
${lecture.title}
</div>
</template>
lectures/list.ts
import { autoinject } from 'aurelia-framework';
import { Router } from 'aurelia-router';
#autoinject()
export class LecturesList {
constructor(private router: Router) {}
navigateToLecture(lecture: {id:number}) {
this.router.navigateToRoute(`lectures`, { id: lecture.id });
}
}
This took me hours of banging my head against the wall and I'm not even sure this will continue to work when I add more routes to the lectures/index.ts, but it works for now and allows me to continue on.
Tried EventEmitter but no chance and so little documentation... Any help appreciated
I have a component called sidebar and another one called header, when you click on a button from the header, it should hide the sidebar... How would you achieve this in angular2 ?
thanks
This is pretty easy with a Service you share between your Components.
For instance a SidebarService:
#Injectable()
export class SidebarService {
showSidebar: boolean = true;
toggleSidebar() {
this.showSidebar = !this.showSidebar;
}
}
In your sidebar component just put a *ngIf with the showSidebar variable from the SidebarService. Also don't forget to add the service in the constructor.
#Component({
selector: 'sidebar',
template: `
<div *ngIf="_sidebarService.showSidebar">This is the sidebar</div>
`,
directives: []
})
export class SidebarComponent {
constructor(private _sidebarService: SidebarService) {
}
}
In the component, where you want to handle the toggling of the sidebar also inject the SidebarService and add the click event with the service method.
#Component({
selector: 'my-app',
template: `
<div>
<button (click)="_sidebarService.toggleSidebar()">Toggle Sidebar</button>
<sidebar></sidebar>
</div>
`,
directives: [SidebarComponent]
})
export class App {
constructor(private _sidebarService: SidebarService) {
}
}
Don't forget to add the SidebarService to the providers in your bootstrap:
bootstrap(App, [SidebarService])
Plunker for example usage
Suppose you have a class you are injecting into a another class or component. Is there a way to watch for changes on an attributed of the dependency you are injecting and act upon it?
For example, say you have the following app:
app.html
<template>
<input type="text" value.bind="item">
<button click.trigger="addToList()">Add</button>
<h3>Modded</h3>
<ul>
<li repeat.for="it of modded">${it}</li>
</ul>
<h3>Original</h3>
<ul>
<li repeat.for="it of dep.items">${it}</li>
</ul>
</template>
app.js
import {bindable, inject} from 'aurelia-framework';
import {Dep} from './dep';
#inject(Dep)
export class App {
constructor(dep) {
this.dep = dep;
}
attached() {
this.modifyItems();
}
addToList() {
this.dep.addItem(this.item);
}
modifyItems() {
this.modded = [];
for (let item of this.dep.items) {
this.modded.push(item.toUpperCase());
}
}
}
dep.js
export class Dep {
constructor() {
this.items = ['one', 'two', 'three'];
}
addItem(item) {
this.items.push(item);
}
}
Now, let's say that some other component modifies Dep.items. Is there a way to watch for changes in app.js on this.dep.items and then call modifyItems()?
Assume modifyItems() is more complex than this example so maybe a value converter is not the best option. (unless it is the only option I guess)
Here is working plunker with the above example: http://plnkr.co/edit/rEs9UM?p=preview
Someone pointed me to the BindingEngine.collectionObserver and it appears that is what I needed.
app.js:
import {inject} from 'aurelia-framework';
import {BindingEngine} from 'aurelia-binding';
import {Dep} from './dep';
#inject(Dep, BindingEngine)
export class App {
constructor(dep, bindingEngine) {
this.dep = dep;
let subscription = bindingEngine.collectionObserver(this.dep.items)
.subscribe((newVal, oldVal) => {
console.debug(newVal, oldVal);
this.modifyItems();
});
}
attached() {
this.modifyItems();
}
addToList() {
this.dep.addItem(this.item);
this.item = '';
}
modifyItems() {
this.modded = [];
for (let item of this.dep.items) {
this.modded.push(item.toUpperCase());
}
}
}
Here is the working pluker: http://plnkr.co/edit/Pcyxrh?p=preview