FontAwesome Icons Not Always Displaying in Nativescript (Vue) App? - vue.js

I am working on an app in Nativescript-vue. The app requires a user to be logged in. When started, the app checks appSettings for whether the user is logged in. If logged in, the user is directed to a menu of choices ("Home"). If user is not logged in, the app loads a login form which validates credentials against a remote DB and then directs the user to the very same menu ("Home").
In both situations, the user is directed to the exact same file, Home.vue. This page consists of 5 or so buttons, each with a FontAwesome icon.
The problem is that the app displays or does not display the icons depending on how the user ends up at the Home.vue menu.
Icons are not displayed when the user is directed on startup to Home.vue (aka appSettings variable shows user is logged in, thus doesn't have to present credentials). Note that drilling further into the app by clicking a button that takes you to another *.vue file that also uses buttons with embedded FontAwesome icons does work.
Icons are displayed correctly when the user is routed to the Home.vue file after presenting valid username / password credentials, both at the Home page and subsequent menus in the app.
MAIN.JS
import Vue from 'nativescript-vue'
// Font Awesome!
import {TNSFontIcon, fonticon} from 'nativescript-fonticon';
TNSFontIcon.debug = true;
TNSFontIcon.paths = {
'fa': './assets/css/fontawesome.min.css',
'far': './assets/css/regular.min.css',
'fas': './assets/css/solid.min.css',
'fab': './assets/css/brands.min.css'
};
TNSFontIcon.loadCss();
Vue.filter('fonticon', fonticon);
import {UserServices} from "./assets/js/UserServices.js"
import Login from "./components/Login.vue";
import Home from "./components/Home.vue"
let user = new UserServices();
new Vue({
render: h => h('Frame', [
h(
(user.getLocalToken()) ? Home : Login
)])
}).$start();
HOME.VUE. (Very stripped down, but still exhibiting the stated behavior)
<template>
<Page class="page" #loaded="loaded">
<StackLayout>
<Button #tap="tapLogoutButton">
<FormattedString>
<Span
class="fas button-icon" stretch="none" :text="'fa-sign-out-alt' | fonticon"
/>
<Span
text=" Logout"
/>
</FormattedString>
</Button>
</StackLayout>
</Page>
</template>
<script>
import Login from "./Login";
import { UserServices } from '../assets/js/UserServices'
let u = new UserServices();
export default {
methods: {
tapLogoutButton(){
if (u.logout()){
this.$navigateTo(Login, {
clearHistory: true
});
};
},
}
};
</script>
Any insight into why the FA icons would appear on a single page (when loaded) depending on how the user ended up there?

You are trying use the plugin your first page before it's ready. loadCss() is an asynchronous function, returns a promise. You must make sure the promise is resolved before using the filter from plugin to render icons.
There are various ways you could solve this
If it's just couple icons in the home / login page, don't use the plugin, directly pass the font code.
you may create an event bus / state, that will hold a boolean value, set it to true upon resolving loadCss() method. Your Home & Login page can rely on the flag, may be with a v-if. It may be few milliseconds for the plugin to process the CSS files.
you may modify the plugin to optionally support synchronous loading,
perhaps even raise a pull request.

I solved this by using the unicode at the text attribute. Binding it to a Vue data.
At the template:
<Label class="fas" :text="file_privacy_police | fonticon"/>
At the <script> tag:
data() {
return {
address_book: "\uf2bb",
file_privacy_police: "\uf570"
};
},
But you can add the unicode directly at the text attribute:
<Label class="fas" :text="'\uf570' | fonticon"/>
This solved my not loading icons problem when already logged in and relaunching the app.

Related

attribute binding in vue 3

I'm new to Vue and currently trying to dynamically change the video or image source link by passing the data in through a prop. I created a component with specific template structure that I would like to pass in the source from the main app.js page. I've tried binding it in both areas but unsure if I'm doing it correctly. I tried using regular divs and stuff to embed the video in app.js and it shows the content perfectly.
parent element contains 'Video' component-
<Video theme="IL" :vidSrc="srcIL.vid"></Video>
import Video from "./components/Video.vue";
export default {
name: "App",
components: {
Video
},
data() {
return {
srcIL: {
vid: "./assets/invi-lines/invisible-lines-film.mp4"
}
};
}
child 'Video component'
<template>
<div class="introVid top">
<video controls :src="vidSrc"></video>
</div>
</template>
<script>
export default {
props: ["theme", "vidSrc"]
};
</script>
This seems like you have it set up properly, and it is hard to know exactly what is causing the issues from the info provided, but I'm going to make a guess that it might be that the asset is not getting bundled.
I tried using regular divs and stuff to embed the video in app.js and it shows the content perfectly
I suspect you had something like:
<video controls src="./assets/invi-lines/invisible-lines-film.mp4"></video>
which would have taken the resource from the assets and packaged it for use.
see relative-path-imports for details.
You can try forcing these to load using require somewhere in the project, which will force the compiler to copy the asset, but really, if you have dynamic assets (assuming there's more than a handful and they can change) you should have them in the public folder already, not in the source folder. So my recommendation is that you move the dynamic assets to the public folder (assuming that was your issue to begin with)

How to layout Vue so pages include header/nav but ability to display stand alone pages such as registration

My current Vue app is laid out as follows:
Such that login Vue would be live under VContent, and aspects of the header and nav are be disabled based on auth state. For example, logout button if store.isAuthenticaaed. See below:
If a Register exists on the login page leading to a registration Vue, how would I break that Vue out of the parent App.vue as to not display the header or nav at all? Should I move my header/wrapper down a level and if so how?
The below answer is totally based on how I understand your requirement, happy to correct if the assumptions are wrong.
Redirecting to which page can be handled at the router configuration.
As per your layout, I can see you have
<VApp>
<VBar />
<VContent >
<router-view />
</VContent>
<VNavigationDrawer />
</VApp>
Now, your store knows whether the user is authenticated or not.
So Why not simply remove <VBar /> and <VNavigation /> using v-if. However, you need to make sure that your state is having the correct state at the initial render.
I can simply create a computed property stating
showBarAndNavigation () {
return store.isAuthenticated && this.$route.name === 'Login' && // anymore handlers
}
<VApp>
<VBar v-if="showBarAndNavigation" />
<VContent >
<router-view />
</VContent>
<VNavigationDrawer v-if="showBarAndNavigation" />
</VApp>

Vue recognize text pattern and replace by href to correct resource

I'm working on a project where I keep a log of key actions by users. For example a log entry is made when a user logs in to the application. I use a Laravel API as backend that takes care of the logging the event in the database and takes care of retrieving log entries to be displayed in the application. An example of a log entry returned for display is the following:
{{user|123|"John Doe"}} logged in at 2020-01-03 11:00:05
Now, I'd like Vue to automatically recognize that this should be replaced by the following:
<router-link to="/user/123">John Doe</router-link> logged in at 2020-01-03 11:00:05
So it automatically becomes a clickable link that navigates to the user profile in this case.
Does Vue offer any such functionality? Any ideas on how to approach this?
Thanks!
Yes, you can bind to to a computed property that will build the path string or data property (then you need to save the builded path in a data section when receving your response):
Template:
<router-link :to="path">{{userName}}</router-link>
script:
export default {
data() {
return {
path: '',
userName: ''
}
},
// OR
computed: {
path() {
<build your path from entry variable>
return <your builded path>
},
userName() {
<extract your user name>
return <extracted user name>
}
}
}
<div v-for="user in users" :key="user.id">
<router-link :to="user.path">{{user.name}}</router-link>
logged in at {{ user.loginTime }}
</div>
I think I will use a v-for to do this, I am wondering what data you got from your Ajax api ?

Vue rendering only part of my App.vue after a login

I am working on a Vue.js application that I am almost done, one major bug left. The bug/issue is that when you go to /login and login to the site you get redirected via a router push (tried replace too) and when this happens I want to render the whole dashboard. Currently since in my App.vue file the router view is a different part it only renders the dashboard info part and not my header or sidebar.
Pretty much imagine a dashboard without a header or sidebar. That's what's rendering. I'd be okay if I could do something like F5 does because then it all would load correctly though taking up to 2 seconds longer on login which is okay by me.
My App.vue file template code
<template>
<div class="fade page-sidebar-fixed page-header-fixed show page-container" v-if="!pageOptions.pageEmpty" v-bind:class="{
'page-sidebar-minified': pageOptions.pageSidebarMinified,
'page-content-full-height': pageOptions.pageContentFullHeight,
'page-with-top-menu': pageOptions.pageWithTopMenu,
'page-sidebar-toggled': pageOptions.pageMobileSidebarToggled,
'has-scroll': pageOptions.pageBodyScrollTop
}">
<Header />
<Sidebar v-if="!pageOptions.pageWithoutSidebar" />
<div id="content" class="content" v-bind:class="{ 'content-full-width': pageOptions.pageContentFullWidth, 'content-inverse-mode': pageOptions.pageContentInverseMode }">
<router-view></router-view>
</div>
</div>
<div v-else>
<router-view></router-view>
</div>
</template>
Looks like I have resolved my issue, it comes from vue-router and how I am doing that if statement in my template code. So in that code I am checking a boolean value then choosing which view to render. So I had though on all of my auth pages I set the value correctly on exit. Turns out not...
This was in my Login.vue file, idea was to have on an exit of the route that it would change the boolean to false which would let me render it right. This was something I did initally but had forgotten about till about 20 minutes ago.
Upon checking this I found the value was not being changed for some reason. So as a work around in the created part of my Dashboard.vue file I set the value to false explicitly
Login.vue
beforeRouteLeave (to, from, next) {
PageOptions.pageEmpty = false;
next();
},
Dashboard.vue
created() {
PageOptions.pageEmpty = false;
...
}
The main idea is to have several base pages each one of them is operate with its own set of internal views.
You have to redirect user to another view, which is the one and only active view and this view can contains sidebar header and main part that also contains router-view, and then! you load any needed components in it.
You have to have something like that:
App component is only contains router view tag and any other pages are load into this.
The routes structure then looks like that:
As you can see, there are two base views load in App view. And then the base view can has a lot of children. The level of nested routes is up to you. Here is the contents of my app Home view:
And the MainContent component which is contains router view only:
The good example of project structure is the one generated with vue-cli. You can use it to simplify dev process with a lot of benefits and good practice solutions.

Aurelia and Multiple Levels of Navigation

I'm building Aurelia app and I have a top navigation for my app built using the router for high level navigation. I also need a separate side navigation for different sections of my app (per-directory).
For instance I have a users section on the site which will have multiple pages (views and view models) in it for different functionality and I need that users section to have it's own side navigation. I would like to have a separate router and navigation side bar per section. The getting started guide shows a child router scenario, but it's only on a given page.
I'd like my app structure to look something like this:
+src
+users
- home.js
- home.html
- users-nav-bar.html (this is what I'm unsure how set up)
- users-nav-bar.js
- users-router.js (not sure if this is possible)
- user-profile.html
- user-profile.js
- user-roles.html
- user-roles.js
+cases
- case-nav-bar.html
- case-nav-bar.js
etc...
Is this possible with Aurelia? Is there another/better way to structure a side nav-bar per section of the app? Can anyone point me to an example?
Definitely possible, I have it working in my sample app. Here is what I have done. Note that this is just a child router\navigation, I have separate nav-bar for the whole app, and this router\navigation is displayed only if the user clicks on the profile page.
//profile.js
export class Profile {
//Business logic related stuff, interact with services, etc
//then
configureRouter(config, router){
config.map([
{
route:["","about-me"] ,
moduleId:"profile/about-me",
title: "About Me",
name : "about-me",
nav:true
},
{
route:"my-travels",
moduleId:"profile/my-travels",
title: "My Travels",
name :"my-travels",
nav:true
},
]);
this.router = router;
}
}
//profile.html
<div class="panel panel-body">
<div class="wizard text-center">
<a repeat.for="row of router.navigation"
class="${row.isActive ? 'active' : ''}"
href.bind="row.href">${row.title}</a>
</div>
<router-view></router-view>
</div>
So without seeing the code, I can only offer suggestions.
Don't worry about having a separate navbar and router class for each child section. for instance, users-navbar and users-router does not sound right to me (again, I am guessing without seeing the code) but if you have just a users.html and and a users.js, you can include your view-model logic AND router information within users.js. Then all users.html does is loop through the configured routes and display a navigation menu. So unless the user clicks on the link which gets him\her to the users page, that navigation menu will not be visible.