How to open multiple pages in the same app? - aurelia

I know that Aurelia is a framework for an SPA but I need to open multiple pages at the same time inside the browser.
I want to host each page (view/viewmodel) within a draggable div and have more than one open at the same time. They will be selected by the User from a menu.
I have looked at viewPorts but cannot see how they will help in this problem.
Is there another way to do this?

Yes, there is a way to do this.
You say pages, but basically they are components. Every component has a HTML (view) and JS (view-model) file. They can be included as custom-elements.
So if you want multiple possible components on one page, all you need to do is create one component that has a placeholder for those views.
Probably, you would want something looking like this:
running Gist example
<template>
<require from="./page1"></require>
<require from="./page2"></require>
<page1></page1>
<hr>
<page2></page2>
</template>
You can create loop for all elements you want to display, if you need multiple instances of the same page, and put a repeat.for on the elements:
HTML:
<template>
<require from="./page1"></require>
<require from="./page2"></require>
<page1 repeat.for="i of page1instances"></page1>
<hr>
<page2 repeat.for="i of page2instances"></page2>
</template>
JS:
export class App {
const page1Instances = 4;
}
Making them drag&droppable works like every other element, there are many solutions for that to be found. Just make the <page1> and <page2> draggable.

Related

Vue Material components in existing application

I'd like to use the md-card material from Vue Material in an existing application. The example on the website (https://vuematerial.io/components/card/) uses the following:
<template>
<div>
<md-card>
...
</md-card>
<md-card md-with-hover>
...
</md-card>
</div>
</template>
When I use this in the HTML page and create a Vue object for the containing div, the components do show, but the layout is not working. I have tinkered with the layout classes, but the behavior is not matching the example. How can I configure the layout in a plain HTML page to match the example's layout behavior? Is the example page adding another layer to the example div to create the layout behavior?
Updated: I tried a similar scenario in JsFiddle, and it works perfectly: https://jsfiddle.net/w9m6q05f/3/ . In my application, the cards are always in a column regardless of the width of the view, and the bottom card is stretched towards the bottom of the view. Do I need to set the class of the containing div? It may be getting overwritten by my application somewhere else.
Update 2: The culprit is which has height: 100%

Modal window in nuxt architecture

Before I was working with Vue2JS and I used to creating modal as just component within App.vue root component for example:
<template>
<div>
<app-navbar></app-navbar>
<router-view></router-view>
<app-footer></app-footer>
<my-modal v-if="someBoolean"></my-modal>
</div>
</template>
Now basing on some custom events or Vuex storage I was able to change someBoolean and trigger when I want modal to be visible.
Since in Nuxt we don't have such thing as root App.vue component I'm wondering how to achieve same as above but with Nuxt.
Of course I could use some package as bootstrap-vue but I don't really want to inject this big package just for that one purpose.
You can write code in layouts/default.vue file and this file works on your defaults, work the code at where you used as a layout of your pages(generally almost everywhere.)
Different approach is use portalvue to render components whereever you want. Nice article here but in Turkish.

How to disable replacing the app root div with the component HTML while using templates

So basically, when using components - the app root passed to the Vue instance gets replaced by whatever HTML is in the component. Is there a way to disable this and just nest the stuff Vue renders inside the app root instead?
for example - if index.html has a wrapper of
<div id="myVueApp"></div>
and I set el: "#myVueApp" on the Vue instance, the whole node will get removed and replaced by whatever I have in my template resulting in
<div id="myComponent">...</div>
Is there a way to make it into
<div id="myVueApp">
<div id="myComponent">...</div>
</div>
Should work. From what I understand, you want to have multiple parts of your Vue app to be splitted up in the rendered HTML output as well, more specifically into multiple divs.
I think this should work if you use multiple Vue instances.
Set up a structure in your HTML file and give them appropriate id's.
Then, create the Vue instances you want and assign each of them to their specific div using el.
However, I can't tell you if this is a good idea and follows the best practice..
Hope this helps!

Aurelia: How can I modify sidebar content from inside a router view?

I'm trying to wrap my head around how "inner components" can adjust the content of "outer components". Let's say I have an application template that looks something like this:
<template>
<div class="sidebar">
<div>Some app-wide content</div>
<div>
<!-- I want to put some view-specific content here -->
</div>
</div>
<div class="main-body">
<router-view></router-view>
</div>
</template>
Each subview wants to render different content to the sidebar. Obviously this would be easy if the subview included the sidebar area itself, but let's say it is important to preserve the structure and we don't want to replicate the boilerplate of the sidebar across every view.
Is there any way for a child view to declare "export this extra component for display in another place?" I imagine something like injecting the parent view and calling a method on it, but I can't figure it out from the documentation.
Simple demo:
It's fairly simple, actually. Just import and inject your sidebar or any other viewmodel and call a method or update a property.
https://gist.run/?id=745b6792a07d92cbe7e9937020063260
Solution with Compose:
If you wanted to get more elaborate, you could set a compose view.bind variable to that your sidebar would pull in a different view/viewmodel based on the set value.
https://gist.run/?id=ac765dde74a30e009f4aba0f1acadcc5
Alternate approach:
If you don't want to import, you could also use the eventAggregator to publish an event from the router view and subscribe to listen to that event from your sidebar and act accordingly. This would work well for a large app setting where you didn't want to tie them too closely together but wanted the sidebar to react correctly to unpredictable routing patterns by always responding when triggers were published.
https://gist.run/?id=28447bcb4b0c67cff472aae397fd66c0
#LStarkey's <compose> solution is what I was looking for, but to help others I think it's worth mentioning two other viable solutions that were suggested to me in other forums:
View ports. You can specify multiple named router views in a template and then populate them by passing in a viewPorts object to the router instead of specifying a single moduleId. The best source of documentation is a brief blurb in the "Cheat Sheet" of the Aurelia docs.
Custom elements. It's a little more "inside-out" but you could define most of the outer content as a custom element that has slots for the sidebar and the main body; each child view would define this custom element and pass in the appropriate pieces.

Vue-js and different layouts

how would one layout the router-views, if you have, lets say 3 different layout to use for you app (e.g. layout for customers, layout for employer and admin-interface).
At the moment i implemented the customer "view" like:
<template>
<div id="app">
<HeaderBar/>
<Navigation></Navigation>
<router-view></router-view>
</div>
</template>
inside the App.vue file. I could use something like:
<div id="app">
<router-view name="header">
<HeaderBar/>
<Navigation></Navigation>
</router-view>
<router-view></router-view>
</div>
</template>
and load different headers for those "subroutes" but this seem's to be odd.
Also what, if i'd like to use an other index.html?
I'm using webpack for this app.
Or would you suggest to create different apps for this?
Many thanks
rene
You could try using dynamic components.
Basically you change which component is being rendered depending on your route.
So it would probably be something like this:
<component v-bind:is="headerComponent"></component>
and then your app can contain heeaderComponent property in data object that has a default value and gets changed when you click on a route that should use different header. Rinse and repeat for the footer.
As for the last question, I think you should only use one app. As it is possible to do and everything is still connected. I'm not sure but I don't know how would you, if need be, communicate between different instances of Vue.