Novice.
I have an app.html that has two custom-elements:
<template>
<require from="../navmenu/navmenu.html"></require>
<require from="./app.css"></require>
<!--We want the nav bar to span the page-->
<div class="container-fluid">
<navmenu router.bind="router"></navmenu>
</div>
<!--We want the media to centre so we use just container-->
<div class="container">
<div className='col-sm-12'>
<div className='row'>
<router-view></router-view>
</div>
</div>
</div>
</template>
The router is bound to the navmenu and so I have routing.
Because I have the following require with the extension .html:
<require from="../navmenu/navmenu.html"></require>
I do not have access to my viewmodel.
If I change the require by removing the .html I loose all my navbar items.
My navbar.ts is:
import { autoinject, bindable, bindingMode } from "aurelia-framework";
import { LoggedInService } from "../components/auth/LoggedInService";
import { customElement } from "aurelia-templating";
#autoinject
#customElement('navmenu')
export class Navmenu {
#bindable public isLoggedIn: boolean = false;
#bindable public userName: string = 'anonymous';
constructor(public loggedInService: LoggedInService) {
this.isLoggedIn = loggedInService.isAuthenticated();
this.userName = loggedInService.getUserName();
}
}
I have added "#binding" to the two variables I want to use but I have no access to them. I have looked at the guide for custom-elements but they are indicating I need to import
How do I access those variables without screwing up my navbar items? or..
How do I access the navmenu viewmodel when the view has been referenced with ".html".
Here is my navmenu.html:
<template bindable="router">
<require from="./navmenu.css"></require>
<div class="main-nav">
<div class="navbar navbar-inverse">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#/home">Jobsledger.API</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li repeat.for="row of router.navigation" class="${ row.isActive ? 'link-active' : '' }">
<a href.bind="row.href" if.bind="!row.settings.nav">${ row.title }</a>
<a href.bind="row.href" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"
if.bind="row.settings.nav">
${row.title}
<span class="caret"></span>
</a>
<ul if.bind="row.settings.nav" class="dropdown-menu">
<li repeat.for="menu of row.settings.nav">
<a href.bind="menu.href">${menu.title}</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
LoggedIn Value: ${ isLoggedIn }
</template>
you need to load your navbar as
<require from="../navmenu/navmenu"></require>
and inject your router to viewmodel
import { autoinject, bindable, bindingMode } from "aurelia-framework"
import { LoggedInService } from "../components/auth/LoggedInService"
import { Router } from 'aurelia-router'
#autoinject
export class NavMenu {
loggedInService: LoggedInService
router: Router
#bindable isLoggedIn: boolean = false
#bindable userName: string = 'anonymous'
constructor(loggedInService: LoggedInService, router: Router ) {
this.isLoggedIn = loggedInService.isAuthenticated()
this.userName = loggedInService.getUserName()
this.router = router
}
}
remove bindable="router" from <template> tag
you can also make router another #bindable in your viewmodel where you dont need to inject Router, but that's for you to try if the above doesnt work for you.
You have to import the viewmodel if you want to use any javascript, so in your case, using <require from="../navmenu/navmenu"></require> is the correct approach.
I think you have misunderstood the meaning of #bindable(). #bindable() means that you can bind that value when you create the element, like so:
<navmenu username.bind="user.name"></navmenu>
Any property declared as public in your viewmodel can be accessed by your view:
export class Navmenu {
public isLoggedIn: boolean = false;
public userName: string = 'anonymous';
constructor(public loggedInService: LoggedInService) {
this.isLoggedIn = loggedInService.isAuthenticated();
this.userName = loggedInService.getUserName();
}
}
<template>
<span>${userName} is logged in: ${isLoggedIn}</span>
</template>
If you want to inject your router into your viewmodel, you shouldn't use viewmodel binding like you did in your example. You can simply inject the router using dependency injection:
import { Router } from "aurelia-routing";
import { autoinject } from "aurelia-framework";
import { LoggedInService } from "../components/auth/LoggedInService";
import { customElement } from "aurelia-templating";
#customElement('navmenu')
#autoinject()
export class Navmenu {
public isLoggedIn: boolean = false;
public userName: string = 'anonymous';
constructor(
public loggedInService: LoggedInService,
public router: Router) {
this.isLoggedIn = loggedInService.isAuthenticated();
this.userName = loggedInService.getUserName();
}
}
And then access it in your viewmodel and/or view.
you need to add a bindable router to your viewmodel
import { bindable, autoinject } from "aurelia-framework";
import { Router } from 'aurelia-router';
export class navmenuCustomElement {
#bindable router: Router;
}
Related
The structure of my code is like this:
So in the Product component, I am making an API call:
<template>
<button class="btn button col-2" #click="addToCart()">
Add to cart
</button>
</template>
<script>
methods:{
addToCart: function () {
let amount = this.itemsCount !== "" ? this.itemsCount : 1;
if(this.variationId != null) {
this.warningMessage = false;
cartHelper.addToCart(this.product.id, this.variationId, amount, (response) => {
this.cartItems = response.data.attributes.items;
});
} else {
this.warningMessage = true;
}
console.log(this.cartItems)
},
}
</script>
And what I am trying to do is the response (this.cartItems) should be shown in Cart component. And my Navbar component:
<template>
<nav class="navbar navbar-expand-lg shadow">
<div class="container navbar-container">
<div class="navbar navbar-profile">
<div class="dropdown">
<button class="btn dropdown-toggle" type="button" id="dropdownCart" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<i class="fa fa-fw fa-cart-arrow-down"></i>
<span></span>
</button>
<div #click="$event.stopPropagation()">
<CartBox :cartItems="cartItems"/>
</div>
</div>
</div>
</div>
</nav>
</template>
<script>
export default {
props: {
cartItems:Object
},
components: {CartBox},
}
And CartBox:
<template>
<Cart/>
</template>
<script>
import Cart from '../components/Cart'
export default {
components: {
Cart
}
}
</script>
And my Cart component:
<template>
<div
class="dropdown-menu cart"
aria-labelledby="triggerId"
>
<div class="inner-cart">
<div>
<div class="cart-items">
<div>
<a class="remove">Remove</a>
</div>
</div>
</div>
<hr/>
<div class="cart-items-total">
<span>Total:</span>
Clear Cart
</div>
<hr/>
<router-link :to="{name: 'order'}" class="btn button-secondary">Go To Cart</router-link>
</div>
</div>
</template>
<script>
export default {
computed: {
},
methods: {
}
};
</script>
I am really confused how to pass the props to sibling component and then the child component but if you could pass it to Cart component, that would really help me.
There are two approaches for your request:
1. Using props, provide and inject
This could be accomplished with Provide / inject, after passing your response to a parent. Basically, you will emit your response from your Product component to a parent, maybe like your App.vue as the prop myData, then you provide it for every child, no matter where it is nested, like this:
provide: {
providedData: this.myData
}
In any child you can now use:
inject: ['providedData']
Please note, that this data will only be available if your Product component received it. The second approach is recommended.
2. Using a store
Using a store like vuex is a bit more complex than approach 1, but it will save a lot of time in the future. You would recieve your response in your Product component, dispatch it to the store and could call the state of information from this store anywhere in your app. See further information in this documentation: Vuex | Getting Started
I have a relation one to many between users table and areas table , when i return profile data i get area_id from users table, i need to get area name using models.
Is there a way to get area name in profile view ?
I tried to call model function in show.vue but it is not working.
User.php
public function area()
{
return $this->belongsTo(Area::class);
}
Area.php
public function users()
{
return $this->hasMany(User::class);
}
show.vue
<template>
<app-layout>
<template #header>
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
Profile
</h2>
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
Area :
</h2>
</template>
<div>
<div class="max-w-7xl mx-auto py-10 sm:px-6 lg:px-8">
<div v-if="$page.props.jetstream.canUpdateProfileInformation">
<update-profile-information-form :user="$page.props.user" />
<jet-section-border />
</div>
<div v-if="$page.props.jetstream.canUpdatePassword">
<update-password-form class="mt-10 sm:mt-0" />
<jet-section-border />
</div>
<div v-if="$page.props.jetstream.canManageTwoFactorAuthentication">
<two-factor-authentication-form class="mt-10 sm:mt-0" />
<jet-section-border />
</div>
<logout-other-browser-sessions-form :sessions="sessions" class="mt-10 sm:mt-0" />
<template v-if="$page.props.jetstream.hasAccountDeletionFeatures">
<jet-section-border />
<delete-user-form class="mt-10 sm:mt-0" />
</template>
</div>
</div>
</app-layout>
</template>
<script>
import AppLayout from '#/Layouts/AppLayout'
import DeleteUserForm from './DeleteUserForm'
import JetSectionBorder from '#/Jetstream/SectionBorder'
import LogoutOtherBrowserSessionsForm from './LogoutOtherBrowserSessionsForm'
import TwoFactorAuthenticationForm from './TwoFactorAuthenticationForm'
import UpdatePasswordForm from './UpdatePasswordForm'
import UpdateProfileInformationForm from './UpdateProfileInformationForm'
export default {
props: ['sessions'],
components: {
AppLayout,
DeleteUserForm,
JetSectionBorder,
LogoutOtherBrowserSessionsForm,
TwoFactorAuthenticationForm,
UpdatePasswordForm,
UpdateProfileInformationForm,
},
}
</script>
You need to load all relationships you want to display manually. Unlike in Blade you can’t just access the relationship with $user->area because $user is not an Eloquent instance but what you are returning as JSON to your Vue instance.
From your controller call $user->load('area'). This will make area available to you.
I had the same problem, but finally i found another trick,
I defined another method in my model and added an attribute
In your case:
Try this:
Area.php
class Area extends Model
{ ....
$appends = ['users'];
public function users()
{
return $this->hasMany(User::class);
}
// define a methode getUsersAttribute()
public function getUsersAttribute(){
return $this->users()->get();
}
Controller.php:
$doctors = User::with('area')->paginate(5);
Vuefile.js
{{user.area.name}}
I want to modify(add or remove node) the parsed ast return by the parse function of #vue/compiler-dom.
I would expect there is a visit method of the ast object, but I can't find one.
Here is the pseudo code what I would expect:
foo.vue
<template>
<div>foo</div>
<div>
<a href="">
bar
<img src="" alt="">
</a>
</div>
<div #click="onClick">foobar</div>
</template>
<script lang="js">
export default {
methods: {
onClick () {},
},
}
</script>
import { parse } from '#vue/compiler-dom';
const ast = parse(content of foo.vue)
ast.visit(...)
I have promble to implement vuex
this my code :
laravel/resources/assets/js/app.js
import router from './routes.js';
import store from './store.js'
require('./bootstrap');
router.beforeEach((to,from,next) => {
if(to.matched.some(record => record.meta.requiresAuth)){
const authUser = JSON.parse(window.localStorage.getItem('authUser'))
if(authUser && authUser.access_token){
next()
}else{
next({
path: '/login',
query: { redirect: to.fullPath }
})
}
}
next()
})
Vue.component('top-menu',require('./components/topMenu.vue'))
const app = new Vue({
el: '#app',
router,store
});
laravel/resources/assets/js/store.js
import Vue from 'vue'
import Vuex from 'vuex'
import userStore from './components/user/userStore.js'
Vue.use(Vuex)
const debug = process.env.NODE_ENV !=='production'
export default new Vuex.Store({
module:{
userStore
},
strict: debug
})
laravel/resources/assets/js/components/user/userStore.js
const state = {
authUser: null
}
const mutations = {
SET_AUTH_USER (state, userObj){
state.authUser = userObj
}
}
const actions ={
setUserObject: ({commit}, userObj) => {
commit('SET_AUTH_USER',userObj)
}
}
export default {
state, mutations, actions
}
this topMenu laravel/resources/assets/js/components/topMenu.vue
<script>
import {mapState} from 'vuex'
export default {
computed: {
mapState(){
userStore: state => state.userStore
}
},
created() {
const userObj = JSON.parse(window.localStorage.getItem('authUser'))
this.$store.dispatch('setUserObject',userObj)
}
}
</script>
<template>
<div>
<pre>{{ userStore }}</pre>
<nav class="navbar navbar-default navbar-static-top" >
<div class="container">
<div class="navbar-header">
<!-- Collapsed Hamburger -->
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#app-navbar-collapse">
<span class="sr-only">Toggle Navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<!-- Branding Image -->
<a class="navbar-brand" href="/">
Laravel
</a>
</div>
<div class="collapse navbar-collapse" id="app-navbar-collapse">
<!-- Left Side Of Navbar -->
<ul class="nav navbar-nav">
</ul>
<!-- Right Side Of Navbar -->
<ul class="nav navbar-nav navbar-right" v-if="userStore.authUser !== null && userStore.authUser.access_token">
<!-- Authentication Links -->
<router-link to="/login" tag="li"><a>Login</a></router-link>
<router-link to="/register" tag="li"><a>Register</a></router-link>
<router-link to="/vendor/profile" tag="li"><a>Profile</a></router-link>
</ul>
</div>
</div>
</nav>
</div>
</template>
if I run the code I have erro
[vuex] unknown action type: setUserObject
[Vue warn]: Property or method "userStore" is not defined on the
instance but referenced during render. Make sure to declare reactive
data properties in the data option. (found in at
/var/www/html/wingding/resources/assets/js/components/topMenu.vue)
[Vue warn]: Error in render function: (found in at
/var/www/html/wingding/resources/assets/js/components/topMenu.vue)
TypeError: Cannot read property 'authUser' of undefined
[Vue warn]: Error in mounted hook: (found in at
/var/www/html/wingding/resources/assets/js/components/Home.vue)
Please help me and thanks!!
The error:
TypeError: Cannot read property 'authUser' of undefined
Should get fixed by adding following null check.
<!-- Right Side Of Navbar -->
<ul class="nav navbar-nav navbar-right" v-if="userStore && userStore.authUser && userStore.authUser.access_token">
I am using angular2.0.0-beta.15. Basically I am trying to load a modal window on click of a button in header. I have put template for modal in an html.What I am trying is, on click of button in parent component, a parameter which indicates which button is pressed, is passed to child component. Based on that I am getting data of modal from db and putting that in modal window.Below is the piece of code.
parent.html
<modal-child id="ContactModal"></modal-child>
<-- code goes here-->
<li [style.display]="!showContact?'none':'inherit'"><a (click)="getContact()" data-remote="false"
data-toggle="modal" data-target="#ContactModal"><i class="fa fa-question"></i>Contact</a></li>
<-- code goes here-->
parent.component.ts
import {Component, Input, provide, DynamicComponentLoader, Injector} from 'angular2/core';
import {ModalChildComponent} from './modal.child.component';
export class ParentComponent{
private id: string;
constructor(private dcl: DynamicComponentLoader, private injector: Injector) {}
getContact() {
this.id = 'Contact';
this.dcl.loadAsRoot(ModalChildComponent, '#ContactModal', this.injector);
}
}
modal.child.component
import {Component, Input} from 'angular2/core';
import {UserService} from '../services/data-services.service';
#Component({
selector: 'modal-child',
templateUrl: './views/templates/modalTemplate.html'
})
export class ModalComponent {
#Input('id') modalId: string;
private contactData: string;
constructor(private _dataService: DataService) {
console.log('id:' + this.modalId);
if (this.modalId === 'Contact') {
this.getContactData();
}
}
getContactData() {
this._dataService.getContact().subscribe(data => {
console.log('contact:' + data);
this.contactData = data;
});
}
}
modalTemplate.html
<!-- Contact -->
<div id="ContactModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content -->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Contact</h4>
</div>
<div class="modal-body">
<div [innerHTML]="contactData"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
When i try above code, it gives me exception like 'Unexpected directive value '[object Object]' on the View of component 'ParentComponent'. Can somebody guide me?