Accessing $route.params in VueJS - javascript

Looking through this documentation:
https://router.vuejs.org/en/essentials/navigation.html
It looks like you can bind the <router-link :to="variableName">Link Text</routerlink> Which is pretty nifty; however, I've had some trouble trying to access route parameters inside of a component I'm trying to build.
So I use this:
<router-link :to="permalink">Title of thing</router-link>
To then direct the router view to pull the forum thread. Using this in the router:
import ForumThread from './views/groupTitle/forumThreadSingle';
// Other routes...
let routes = [
{
path: '/groupTitle/th/:id',
component: ForumThread,
}
];
I can see in the forumthread component that $route.params.id is being passed too it; however, when I try to access it like this:
console.log('The id is: ' + $route.params.id);
It's unable to find the params portion of the object.
VueJS is pretty new to me as well as JavaScript itself. All the examples I've seen show the templates being inline with the router file which is something I am trying to prevent to help keep my code readable and clean.
What adjustments can I make so that I can pass properties to the template file?
Thanks!

If you're using the Vue Loader setup (which has <template></template> tags in the files), you need to use this to reference the $router, if you're doing so within the <script></script> part of the file.
console.log('The id is: ' + this.$route.params.id);

For and one wanting to get params in vue 3 with composition API for vue-router 4.x, it can be achieved using useRoute.
import {useRoute} from "vue-router";
setup(){
const route = useRoute();
const id = route.params.id;
}

Related

Elixir Phoenix - How to create and import javascript files into specific templates

I'm currently experimenting with the Elixir Phoenix framework together with Liveview. For my project, I would like to write some Javascript code that is only imported on certain pages (templates). Although this seems like something very trivial, I am struggling to get it working.
At this moment I created a seperate Javascript file as such assets/js/custom.js. After doing this, I added the following line to my root.html.heex as a first test to see if this already works. For this line, I simply looked at how app.js is imported.
<script defer phx-track-static type="text/javascript" src={Routes.static_path(#conn, "/assets/custom.js")}></script>
The next step would then be to figure out how to import it in a seperate template instead of the root. However, this first test already failed resulting in the following error:
[debug] ** (Phoenix.Router.NoRouteError) no route found for GET /assets/custom.js (MyAppWeb.Router)
(my_app 0.1.0) lib/phoenix/router.ex:405: MyAppWeb.Router.call/2
(my_app 0.1.0) lib/my_app_web/endpoint.ex:1: MyAppWeb.Endpoint.plug_builder_call/2
(my_app 0.1.0) lib/plug/debugger.ex:136: MyAppWeb.Endpoint."call (overridable 3)"/2
(my_app 0.1.0) lib/my_app_web/endpoint.ex:1: MyAppWeb.Endpoint.call/2
(phoenix 1.6.15) lib/phoenix/endpoint/cowboy2_handler.ex:54: Phoenix.Endpoint.Cowboy2Handler.init/4
(cowboy 2.9.0) c:/Users/arnod/Desktop/phoenixtut/my_app/deps/cowboy/src/cowboy_handler.erl:37: :cowboy_handler.execute/2
(cowboy 2.9.0) c:/Users/arnod/Desktop/phoenixtut/my_app/deps/cowboy/src/cowboy_stream_h.erl:306: :cowboy_stream_h.execute/3
(cowboy 2.9.0) c:/Users/arnod/Desktop/phoenixtut/my_app/deps/cowboy/src/cowboy_stream_h.erl:295: :cowboy_stream_h.request_process/3
(stdlib 4.0.1) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
Could somebody help me figure this one out? How does one add seperate Javascript files and only import them in specific templates?
You can import all your custom javascript once in app.js, assign them as hooks which you can then use in your (live) views, wherever needed, for example;
custom.js
export const SomeFunction = {
mounted() {
alert("some function ran!");
}
}
app.js snippet
...
import {SomeFunction} from "./custom.js"
let Hooks = {}
Hooks.SomeFunction = SomeFunction
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}, hooks: Hooks})
...
Then in your live view render function (or template) add the hook
...
def render(assigns) do
~H"""
...
<div id="my-hook" phx-hook="SomeFunction"></div>
...
end
...
More about javascript interoperability can be found on the Phoenix hex page here. You can tie them to all sorts of phoenix events.
nb. Also note that #conn isn't available in live views, only #socket is.

How to create a global string in a vue (webpack) project

In my vue project I have a default image that should show up in places around the app when an image is missing or hasn't been uploaded yet. I have various class files and component calls that want to use the same image.
What is the best way to create a global variable that I can access from anywhere? I can't put it in the store because my class files (I'm using vuex-orm) are loaded before the store is declared. I would prefer not to put it in the window because I want to have a single word variable that I can call (defaultImg as opposed to window.my_project.globals.defaultImg). I could put it in .env but I want this to be checked into the repository and the same across environments so that doesn't seem right either.
What is the best way to provide a simple global string to all files in my vue project?
Are you using Vue 2 or 3? TL;DR best approach is to create a component.
Quick Fix
You could take the approach described in the documentation for creating plugins:
https://vuejs.org/guide/reusability/plugins.html#introduction
If you didn't want to go down the convoluted route of creating a separate plugin file just to store a single string you could probably just do something like this in your entry file where you initialize the app:
Vue 3:
app.config.globalProperties.$defaultImg = '/path/to/image.png'
Vue 2:
Vue.prototype.$defaultImg = '/path/to/image.png'
And use this in your templates like
<img :src="$defaultImage">
Best Solution
However, I think the best and the most 'Vue' way would be to create an image component which displays a given image, or the default image if src is nullish:
Vue 2 & 3
<template>
<img :src="srcOrDefault">
<template>
Vue 3 Composition API:
<script>
const defaultImg = '/path/to/image.png'
const props = defineProps({
src: String
});
const srcOrDefault = computed(() => {
return props.src || defaultImg
})
</script>
Vue 2 & Vue 3 Options API:
<script>
const defaultImg = '/path/to/image.png'
export default {
props: {
src: String
},
computed: {
srcOrDefault() {
return this.src || defaultImg
}
}
}
</script>

How to properly store non-reactive and static data in an vue?

Greetings to the community! This is my first question on the StackOverflow.
I use vue.js-v2 and webpack. I need to have immutable data available for child components. The components are loaded via the vue-router. Different pages need the same data.
I import data from a JSON file and integrate it into vue with a "main.js":
//main.js
import Vue from 'vue'
import ...
import myData from './path/file.json' // [{},{},{}...]
Vue.prototype.$storage = myData
new Vue({ router, .....
Then I use in different components something like:
//pageX.vue
...
this.componentVar = this.$storage.filter((x) => x.name === 'needName')
And somehow it works. I worry if I'm doing the right thing. I am afraid of duplicating data in components or something like that, because my knowledge of javascript is deplorable :(
You have to use Vuex to store that data.. wheater immutable or not a state of an app has to a single absolute source of truth and no alternative compared to vuex can help you in this case

Pass data from blade file directly to Vue instance

I am working on a Vue application that's living in a Laravel project. I bind my vue instance to an id that's placed in a blade file.
What I would like to do is to pass the logged user to my Vue instance from Laravel/blade. Is there a way to do this? I know you can pass data through props but this here is just a regular div with an id of #root that's binding the Vue instance. I know how to get the logged user, but I am specific looking for an way to directly pass the data from blade to my vue instance.
app.js
// Require the deps from laravel (jQuery, axios, Bootstrap)
require('./bootstrap');
// Import vue deps
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter)
// Import the router & routes
import router from './routes'
// Init a new vue instance
const root = new Vue({
el: '#root',
data: {
User: name here..
},
router
});
Blade
#extends('layouts.app')
#section('content')
<!-- pass user below -->
<div id="root"></div>
#endsection
In your blade file, pass the logged user information to a javascript global variable. Let's say you just want the user id and name:
<script>
window.auth_user = {!! json_encode([
'id' => auth()->user()->id,
'name' => auth()->user()->name
]) !!};
</script>
Then in your javascript, you can access the auth_user global variable.
For example, to log the user name:
console.log(auth_user.name)
or
console.log(window.auth_user.name)
You have few options (I think I not list all) e.g:
You can pass data by converting them to json and write as HTML element or attribute and then read it from vue using e.g. document.querySelector(...) - more info here: Best way to store JSON in an HTML attribute?
You can change a littlebit architecture and create separate (Restful) API which your vue components will be use via ajax to read data (e.g. you can create GET api/v1/currentUser do read current logged user)
Completly change your architecture - to "microservices" - so in laravel only create Restful API, and creatte SEPEARATE project with vue (and NO laravel) user interface which use that API (it is modern approach to separation backend from frontend). You will face CORS problem in this approach but its no so hard (only at first time).
You might want to take a look at the PHP-Vars-To-Js-Transformer
package. You can use it either in your controller or in a #php directive.
Probably not a good practice with VueJS though.

Importing javascript file for use within vue component

I am working on a project that requires using a js plugin. Now that we're using vue and we have a component to handle the plugin based logic, I need to import the js plugin file within the vue component in order to initialize the plugin.
Previously, this was handled within the markup as follows:
<script src="//api.myplugincom/widget/mykey.js
"></script>
This is what I tried, but I am getting a compile time error:
MyComponent.vue
import Vue from 'vue';
import * from '//api.myplugincom/widget/mykey.js';
export default {
data: {
My question is, what is the proper way to import this javascript file so I can use it within my vue component?
...
Include an external JavaScript file
Try including your (external) JavaScript into the mounted hook of your Vue component.
<script>
export default {
mounted() {
const plugin = document.createElement("script");
plugin.setAttribute(
"src",
"//api.myplugincom/widget/mykey.js"
);
plugin.async = true;
document.head.appendChild(plugin);
}
};
</script>
Reference: How to include a tag on a Vue component
Import a local JavaScript file
In the case that you would like to import a local JavaScript in your Vue component, you can import it this way:
MyComponent.vue
<script>
import * as mykey from '../assets/js/mykey.js'
export default {
data() {
return {
message: `Hello ${mykey.MY_CONST}!` // Hello Vue.js!
}
}
}
</script>
Suppose your project structure looks like:
src
- assets
- js
- mykey.js
- components
MyComponent.vue
And you can export variables or functions in mykey.js:
export let myVariable = {};
export const MY_CONST = 'Vue.js';
export function myFoo(a, b) {
return a + b;
}
Note: checked with Vue.js version 2.6.10
try to download this script
import * from '{path}/mykey.js'.
or import script
<script src="//api.myplugincom/widget/mykey.js"></script>
in <head>, use global variable in your component.
For scripts you bring in the browser way (i.e., with tags), they generally make some variable available globally.
For these, you don't have to import anything. They'll just be available.
If you are using something like Webstorm (or any of the related JetBrains IDEs), you can add /* global globalValueHere */ to let it know that "hey, this isn't defined in my file, but it exists." It isn't required, but it'll make the "undefined" squiggly lines go away.
For example:
/* global Vue */
is what I use when I am pulling Vue down from a CDN (instead of using it directly).
Beyond that, you just use it as you normally would.
I wanted to embed a script on my component and tried everything mentioned above, but the script contains document.write. Then I found a short article on Medium about using postscribe which was an easy fix and resolved the matter.
npm i postscribe --save
Then I was able to go from there. I disabled the useless escape from eslint and used #gist as the template's single root element id:
import postscribe from 'postscribe';
export default {
name: "MyTemplate",
mounted: function() {
postscribe(
"#gist",
/* eslint-disable-next-line */
`<script src='...'><\/script>`
);
},
The article is here for reference:
https://medium.com/#gaute.meek/how-to-add-a-script-tag-in-a-vue-component-34f57b2fe9bd
For anyone including an external JS file and having trouble accessing the jQuery prototype method(s) inside of the loaded script.
Sample projects I saw in vanilla JS, React and Angular were simply using:
$("#someId").somePlugin(options)
or
window.$("#someId").somePlugin(options)
But when I try either of those in my VueJS component I receive:
Error: _webpack_provided_window_dot$(...).somePluginis not a function
I examined the window object after the resources had loaded I was able to find the jQuery prototype method in the window.self read-only property that returns the window itself:
window.self.$("#someId").somePlugin(options)
Many examples show how to load the external JS file in VueJS but not actually using the jQuery prototype methods within the component.

Categories

Resources