Show Hide Header based on their respective home page with vuejs - html

By default I have header-one which can be seen in all the pages. Then there comes header-two and header-three which are only shown when there respective home pages are been opened . Is there anyway we can do by condition if the path is '/home-one' not '/home-two' and '/home-three' then show header-v1
//App.vue//
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template>
<v-app>
<header-v1></header-v1>
<header-v2></header-v2>
<header-v3></header-v3>
<router-view></router-view>
<emb-footer-V1></emb-footer-V1>
</v-app>
</template>

Several ways you could approach this using props, a route watcher, meta, etc.
Here's an example using meta on each route:
Vue.use(VueRouter)
const routes = [{
path: '/',
component: {
template: '<div>home page</div>'
}
}, {
path: '/home-one',
component: {
template: '<div>home page one</div>'
},
meta: {
header: 1
}
},
{
path: '/home-two',
component: {
template: '<div>home page two</div>'
},
meta: {
header: 2
}
},
{
path: '/home-three',
component: {
template: '<div>home page three</div>'
},
meta: {
header: 3
}
}
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<h1 v-if="$route.meta.header === 1">I'm visible on home page one</h1>
<h2 v-else-if="$route.meta.header === 2">I'm visible on home page two</h2>
<h3 v-else-if="$route.meta.header === 3">I'm visible on home page three</h3>
<p>
<router-link to="/">Home</router-link>
<router-link to="/home-one">Home One</router-link>
<router-link to="/home-two">Home Two</router-link>
<router-link to="/home-three">Home Three</router-link>
</p>
<router-view></router-view>
</div>

Related

How to define variables in Vue router to be used inside components?

I have a navbar on top and a <router-view> right below it (as seen in App.vue). I want the title inside the navbar to change depending on the route/view I am on. Since my views in the <router-view> do not contain the title itself, I need to define them somewhere. An example for the scenario could be when reaching the route /login, the title in the navbar changes to "Login".
How do I achieve this?
When searching for a solution, I came across a lot of page title questions. I am not talking about the document.title assignment, however, that could be a solution, but not a perfect one. What if I wanted the title to be something else than the document title..
App.vue:
<template>
<Menu :isActive="isMenuActive" />
<Navbar #toggle:hamburger="onHamburgerToggle($event)" />
<router-view />
</template>
Vue router allows you to attach any information you want to any route using Route Meta Fields
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
meta: { title: "FOO" }
}
]
})
You can access the information for currently active route in any component using $route variable
const child = Vue.component('child', {
template: `
<div>
Child component ("{{ $route.meta.title }}")
</div>
`
})
const router = new VueRouter({
mode: 'history',
routes: [
{
name: 'route1',
path: '/route1',
component: child,
meta: { title: 'Hello from route 1!'}
},
{
name: 'route2',
path: '/route2',
component: child,
meta: { title: 'Hello from route 2!'}
},
]
})
new Vue({
el: '#app',
router,
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<router-link to="/route1">Route 1</router-link>
<router-link to="/route2">Route 2</router-link>
<h4> Current route: {{ $route.meta.title }} </h4>
<router-view></router-view>
</div>
Every component can access the $route object, so you could use that directly in your template. Or you can access that object in the script and do something with it.
Imagine your routes have the name property:
router/index.js
routes: [
{ path: '/', name: 'home', component: Home },
{ path: '/foo', name: 'foo', component: Foo },
{ path: '/bar', name: 'bar', component: Bar }
]
You could show that name in the template with no script necessary:
Navbar.vue
<template>
<div>Title: {{ $route.name }}</div>
</template>
(meta is also a good idea here as explained in #MichalLevý's answer.)
Or you could access the route object in the script and create a title however you want.
Navbar.vue (Composition API)
<template>
<div>Title: {{ title }}</div>
</template>
<script>
import { ref } from 'vue';
import { useRoute } from 'vue-router';
export default {
setup() {
const route = useRoute();
const title = ref('My title ' /* Do something with `route` */);
return { title }
}
}
</script>

How load html template in vuejs

I use vue.js and vue-router.js.
I added both of files to a html page
This is my component for load template...
const Dashboard = {template: "<strong>"}
But I want load html page dynamically and with HTTP URL.
const Dashboard = {template: "How load html page with url(http)"}
Can anyone guide me?
you could define a component similar to this
Vue.component('dynamic-component', {
props: {
contentURL: String,
},
template: `<div v-html='inner_html'></div>`,
computed: {
inner_html() {
return // http call to get html value utilizing this.contentURL
},
},
});
then from the router
{
path: '/path/option-a',
components: {
DynamicComponent
},
props: {
contentURL: `https://some-resource/option-a`
}
},
{
path: '/path/option-b',
components: {
DynamicComponent
},
props: {
contentURL: `https://some-resource/option-b`
}
}
For creating layers, you can create vue component and use slot
Layout.vue
<template>
Header
AnyComponents
<slot />
Footer
</template>
and in your page component you should import your layout and wrap
MainPage.vue
<template>
<MainLayout>
Here is your conntent of page or router
<router-view />
</MainLayout>
</template>
<script>
import MainLayout from 'layout.vue';
export default {
components: {
MainLayout
}
}
</script>
And now for render your page you should use your page in router
example of router.js
import Vue from 'vue';
import Router from 'vue-router'
import MainPage from 'MainPage.vue';
Vue.use(Router)
export default new Router({
routes: [{
path: '/',
component: MainPage,
}]
})
If you want to insert html to your page, use v-html
<div class="content" v-html="dashboard.template">
</div>

How to dynamically change content of component with JSON?

I am creating my design portfolio using Vue CLI 3. The architecture of my website is very simple. I have a home page, about page, work page, and several individual project pages:
Home
About
Work
Project
Project
Project
The work page consists of several links that would click through to the individual project pages. The work component is set up like so:
<template>
<div>
<projectLink v-for="data in projectLinkJson" />
</div>
</template>
<script>
import projectLink from '#/components/projectLink.vue'
import json from '#/json/projectLink.json'
export default {
name: 'work',
data(){
return{
projectLinkJson: json
}
},
components: {
projectLink
}
}
</script>
As you can see, I'm importing JSON to dynamically render the content. Next, the projectLink component can be seen in the code block below. Within this component I am passing a param into <router-link> called projectName
<template>
<router-link :to="{ name: 'projectDetails', params: { name: projectName }}">
<h1>{{ title }}</h1>
</router-link>
</template>
<script>
export default {
name: 'projectLink',
props: {
title: String,
projectName: String
}
}
</script>
My routes.js file is setup like so:
const routes = [
{ path: '/', component: home },
{ path: '/about', component: about },
{ path: '/work', component: work },
{
path: "/work/:name",
name: "projectDetails",
props: true,
component: projectDetails
},
];
and my JSON is like so:
{
"0": {
"title": "test",
"projectName": "test"
}
}
Lastly, my projectDetails component is the component that is where I am having this issue:
<template>
<div>
<div
v-for="(data,index) in projectDetailsJson" v-if="index <= 1">
<h1>{{ data.title }}</h1>
<p>{{ data.description }}</p>
</div>
</div>
</template>
<script>
import json from '#/json/projectDetails.json'
export default {
name: 'projectDetails',
data(){
return{
projectDetailsJson: json
}
},
props: {
description: String,
title: String
}
}
</script>
I am successfully routing to the URL I want, which is /project/'name'. I want to use the projectDetails component as the framework for each of my individual project pages. But how do I do this dynamically? I want to retrieve data from a JSON file and display the correct object from the array based on the name that was passed to the URL. I do not want to iterate and have all of the array display on the page. I just want one project to display.
Quick solution:
projectDetails.vue
<template>
<div>
<div>
<h1>{{ projectDetails.title }}</h1>
<p>{{ projectDetails.description }}</p>
</div>
</div>
</template>
<script>
import json from '#/json/projectDetails.json';
export default {
name: 'projectDetails',
props: {
name: String,
},
data() {
return {
projectDetails: Object.values(json).find(project => project.title === this.name),
};
},
};
</script>
In my opinion, a better solution:
I don't get the idea that you keep project data in 2 separate JSON files. During compilation, both files are saved to the resulting JavaScript file. Isn't it better to keep this data in 1 file? You don't have to use all of your data in one place. The second thing, if you have a project listing then you can do routing with an optional segment, and depending on whether the segment has a value or not, display the listing or data of a particular project. Then you load project data only in one place, and when one project is selected, pass its data to the data rendering component of this project. Nowhere else do you need to load this JSON file.
routes.js
import home from '#/components/home.vue';
import about from '#/components/about.vue';
import work from '#/components/work.vue';
const routes = [
{path: '/', name: 'home', component: home},
{path: '/about', name: 'about', component: about},
{path: '/work/:name?', name: 'work', component: work, props: true},
];
export default routes;
work.vue
<template>
<div>
<project-details v-if="currentProject" :project="currentProject"/>
<projectLink v-else
v-for="project in projects"
v-bind="project"
v-bind:key="project.projectName"
/>
</div>
</template>
<script>
import projectLink from './projectLink';
import projectDetails from './projectDetails';
import json from '#/json/projectLink.json';
export default {
name: 'work',
props: {
name: String,
},
data() {
return {
projects: Object.values(json),
};
},
computed: {
currentProject() {
if (this.name) {
return this.projects.find(
project => project.projectName === this.name,
);
}
},
},
components: {
projectLink,
projectDetails,
},
};
</script>
projectDetails.vue
<template>
<div>
<div>
<h1>{{ project.title }}</h1>
<p>{{ project.description }}</p>
</div>
</div>
</template>
<script>
export default {
name: 'projectDetails',
props: {
project: Object,
},
};
</script>
projectLink.vue (changed only one line)
<router-link v-if="projectName" :to="{ name: 'work', params: { name: projectName }}">
A full working example:
Vue.component("navigation", {
template: "#navigation"
});
const Projects = {
template: "#projects",
props: ["projects"]
};
const Project = {
template: "#project",
props: ["project"]
};
const HomePage = {
template: "#home"
};
const AboutPage = {
template: "#about"
};
const WorkPage = {
data() {
return {
projects: [{
slug: "foo",
name: "Foo",
desc: "Fus Ro Dah"
},
{
slug: "bar",
name: "Bar",
desc: "Lorem Ipsum"
}
]
};
},
props: {
slug: String
},
template: "#work",
components: {
Projects,
Project
},
computed: {
currentProject() {
if (this.slug) {
return this.projects.find(project => project.slug === this.slug);
}
}
}
};
const router = new VueRouter({
routes: [{
path: "/",
name: "home",
component: HomePage
},
{
path: "/about",
name: "about",
component: AboutPage
},
{
path: "/work/:slug?",
name: "work",
component: WorkPage,
props: true
}
]
});
new Vue({
router,
template: "#base"
}).$mount("#app");
ul.nav {
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
background-color: #333;
}
ul.nav>li {
float: left;
}
ul.nav>li>a {
display: block;
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
}
ul.nav>li>a:hover {
background-color: #111;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.1.3/vue-router.min.js"></script>
<div id="app"></div>
<script type="text/x-template" id="base">
<div id="app">
<div>
<navigation></navigation>
<router-view></router-view>
</div>
</div>
</script>
<script type="text/x-template" id="navigation">
<ul class="nav" id="navigation">
<li>
<router-link :to="{name: 'home'}">Home</router-link>
</li>
<li>
<router-link :to="{name: 'about'}">About</router-link>
</li>
<li>
<router-link :to="{name: 'work'}">Work</router-link>
</li>
</ul>
</script>
<script type="text/x-template" id="home">
<div id="home">This is Home Page</div>
</script>
<script type="text/x-template" id="about">
<div id="about">This is About Page</div>
</script>
<script type="text/x-template" id="work">
<div id="work">
<project v-if="currentProject" :project="currentProject"></project>
<projects v-else :projects="projects"></projects>
</div>
</script>
<script type="text/x-template" id="projects">
<div id="projects">
<ul>
<li v-for="project in projects" :key="project.slug">
<router-link :to="{name: 'work', params:{ slug: project.slug}}">{{project.name}}</router-link>
</li>
</ul>
</div>
</script>
<script type="text/x-template" id="project">
<div id="project">
<h2>{{project.name}}</h2>
<p>{{project.desc}}</p>
</div>
</script>
Great work thus far, Austin! You're very close having this working. There are a few different ways you could parse out the correct data from your JSON file into the projectDetails component, but I'll just demo my preferred way.
First, you're going to need a bit of vanilla JS to search through your JSON file and return only the row that you want. I would do this as a method since the data isn't going to be changing or requiring the component to re-render. So, after your props, I would add something like this:
methods: {
findProject(projectName) {
return Object.values(json).find(project => project.title === projectName)
}
}
Note that this is going to return the first project that matches the project name. If you have projects with the exact same project name, this won't work.
Next, you'll just need to update the default value of projectDetailsJson to call this method and pass the route's project name. Update data with something like this:
data() {
return {
projectDetailsJson: this.findProject(this.$route.params.name)
}
}
If that doesn't work, we may need to set the projectDetailsJson in the created lifecycle hook, but try the above code first.
If I understood correctly, you want to keep a parent component as a layout for all of your page?
If I always understood correctly, you must use the children property of vuerouter
https://router.vuejs.org/guide/essentials/nested-routes.html
import layout from 'layout';
const projectRoute = {
path: '/project',
component: Layout, // Load your layout
redirect: '/project/list',
name: 'Project',
children: [
{
path: "list", // here the path become /project/list
component: () => import('#/views/project/List'), // load your components
name: "List of project",
},
{
path: "detail/:id",
component: () => import('#/views/project/Detail'),
name: "Detail of project",
}
],
};
So you can create your layout and add everything you want, this will be available on all child components, and you can use $emit, $refs $props ect...
+
You can create an file routes/index.js and create folder routes/modules . Inside this, you can add your routes/modules/project.js and load the modules in routes/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
import projectRoutes from "./modules/project";
const routes = [
projectRoutes,
{
// other routes....
},
]
export default new VueRouter({
routes,
mode: 'history',
history: true,
});
#see the same doc : https://router.vuejs.org/guide/essentials/nested-routes.html
Finally, you just have to do the processing on the layout, and use the props to distribute the values ​​both in detail and in the project list; and use the filter methods described just above
I hope I have understood your request, if this is not the case, let me know,
see you
Edit: Here is a very nice architecture with vue, vuex and vuerouter. maybe inspire you
https://github.com/tuandm/laravue/tree/master/resources/js
For everyone, to take this one step further. How would you show only the projectLinks that match the current URL? So if I have three different JSON projectTypes: design, code, motion. If the URL contains motion in it, how do I filter my projectLink components to show only those that have a matching JSON value of either design, code or motion. Essentially I'm just trying to filter.

Render Component in iframe using vuejs without src attribute

<iframe id="frame" width="100%" height="100%">
</ifrme>
I want to render component in this iframe. Is there any option of creating html element or rendering component in iframe?
new Vue({
el:'#frame',
store:store,
router:router,
render: component
})
The easiest way for me is to use srcdoc attribute. It loads raw html overriding src attribute.
<template>
<iframe :srcdoc="html"></iframe>
</template>
Update: More detail example: Consider a textarea for a user html input and want to display in an iframe.
<template>
<div id="app">
<textarea v-model="html"></textarea>
<iframe :srcdoc="html"></iframe>
</div>
</template>
<script>
export default {
name: "App",
data(){
return {
html:"<h1>Hello I am H1 block</h1>"
}
}
};
</script>
You can refer below link That helped me a lot.
Here is the link and the code snippets.
Vue.component('i-frame', {
render(h) {
return h('iframe', {
on: { load: this.renderChildren }
})
},
beforeUpdate() {
//freezing to prevent unnessessary Reactifiation of vNodes
this.iApp.children = Object.freeze(this.$slots.default)
},
methods: {
renderChildren() {
const children = this.$slots.default
const body = this.$el.contentDocument.body
const el = document.createElement('DIV') // we will mount or nested app to this element
body.appendChild(el)
const iApp = new Vue({
name: 'iApp',
//freezing to prevent unnessessary Reactifiation of vNodes
data: { children: Object.freeze(children) },
render(h) {
return h('div', this.children)
},
})
iApp.$mount(el) // mount into iframe
this.iApp = iApp // cache instance for later updates
}
}
})
Vue.component('test-child', {
template: `<div>
<h3>{{ title }}</h3>
<p>
<slot/>
</p>
</div>`,
props: ['title'],
methods: {
log: _.debounce(function() {
console.log('resize!')
}, 200)
},
mounted() {
this.$nextTick(() => {
const doc = this.$el.ownerDocument
const win = doc.defaultView
win.addEventListener('resize', this.log)
})
},
beforeDestroy() {
const doc = this.$el.ownerDocument
const win = doc.defaultView
win.removeEventListener('resize', this.log)
}
})
new Vue({
el: '#app',
data: {
dynamicPart: 'InputContent',
show: false,
}
})
https://jsfiddle.net/Linusborg/ohznser9/
I've tried and haven't found a way to mount vue directly on #iframe.
Yet, you can add div to #iframe and mount to that:
// create iframe element
var iframe = document.createElement('iframe')
iframe.id = 'iframe'
// place iframe inside page html
document.documentElement.insertBefore(iframe, document.querySelector('html').firstChild)
// append div to iframe
var container = document.createElement('div')
container.id = 'container'
iframe.contentWindow.document.body.appendChild(container)
// render vue component inside iframe on #container
new Vue({
el: container,
render: h => h(component)
})
Result:
<html>
<iframe id="iframe">
#document
<html>
<head>
</head>
<body><!-- <-- here was <div id="container"></div> -->
<div class="message" style="color: orange;">Hello from Vue component!</div>
</body>
</html>
</iframe>
<head>
</head>
<body>
</body>
</html>
P.s. I've used this code in chrome extension content scripts (javascript injected into pages). If you're going to use
it elsewhere make sure not to break Same-origin policy.
new Vue({
el:'#frame',
store:store,
router:router,
render: component
})
just try to give a name to your route view.
Hope it works

Custom Directives and Template doesn't work

I'm trying to make a custom directive that will show some elements that i previously declared in the MainController
HTML body:
<body ng-app="myApp" ng-controller="MainController">
<h1> Choose your Car </h1>
<div ng-repeat="car in cars">
<my-pattern info="car"></my-pattern>
</div>
<script src="js/MainController.js"></script>
<script src="js/myPattern.js"></script>
</body>
MainController:
angular.module('myApp').controller('MainController',function($scope) {
$scope.cars=[
{
icon: 'imgs/lamborghini.jpg',
name: 'Lamborghini',
price: 100000
},
{
icon: 'imgs/audi.png',
name: 'Audi',
price: 80000
}
];
});
Custom Directive
angular.module('myApp').directive('myPattern', function() {
return{
restrict: 'E',
scope: {
info: '='
},
templateUrl: 'js/directives/myPattern.html'
};
});
Template:
<img ng-src="{{info.icon}}">
<h2>{{info.name}}</h2>
<p>{{info.price}}</p>
If i don't use the directive but i just make the output whit the expressions <h2>{{car.name}}</h2> like this it work but with the custom directive it doesn't show me nothing.
I have all in different files.
This is working for me. There must be a issue with the location of your template with respect to your current HTML:
var app = angular.module("myApp", []);
angular.module('myApp').controller('MainController', function($scope) {
$scope.cars = [{
icon: 'imgs/lamborghini.jpg',
name: 'Lamborghini',
price: 100000
}, {
icon: 'imgs/audi.png',
name: 'Audi',
price: 80000
}];
});
angular.module('myApp').directive('myPattern', function() {
return {
restrict: 'E',
scope: {
info: '='
},
templateUrl: 'js/directives/myPattern.html'
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MainController">
<h1> Choose your Car </h1>
<div ng-repeat="car in cars">
<my-pattern info="car"></my-pattern>
</div>
<script type="text/ng-template" id="js/directives/myPattern.html">
<img ng-src="{{info.icon}}">
<h2>{{info.name}}</h2>
<p>{{info.price}}</p>
</script>
</div>
I solved, i didn't synchronize the directives in the Custom Directive and in the body HTML. The code was right but i make a mistake with the calling script of the directive:
<script src="js/directives/myPattern.js"></script>