meteor dynamic meta tags - dynamic

Well, i need some way to have a dynamic meta tags for my app, im creating a cms-blog so ill need to change the meta desc/keywords/title etc at every post,im using iron-router.
i have an idea how to do so using not completely sure:
<template name="post">
{{metaTitle}}
</template>
Template.post.metaTitle = function (this) {
document.title = this;
}
(iron-router version)
this.route('post', {
path: '/',
....
data: function () {
return Posts.findOne({_id: this.params._id});
}
//Posts holds post documents with a fields like: "metaTitle" "metaKeywords" etc
});
so if a client routes to "/" and the Posts collection holds a post with id of "/"
and the document holds metaTitle:"Post 1"
will this proceed to the template.post.metaTitle helper
and the title will be "Post 1"?
is there a better way?
and doing similar stuff to the keywords etc.

ok , i have manged to do this, here is what i'v done:
html:
<template name="posts">
{{metaTitle}}
{{metaDesc}}
{{metaKeywords}}
{{>home}}
{{#each posts}}
</div>
<a href="{{pathFor 'post'}}">
<div class="small-12 medium-12 large-12 columns">
<div class="post">
<div class="small-12 medium-12 large-12 columns">
<h4 class="left">{{author}}</h4>
<h4 class="right">{{date}}</h4>
</div>
<h2>{{title}}</h2>
<p>{{desc}}</p>
</div>
</div>
</a>
<hr/>
{{/each}}
</template>
router (iron-router):
this.route('posts', {
path: '/',
waitOn:function(){
NProgress.start();
Meteor.subscribe("Teams");
},
before: function () {
Session.set("adding_group", false);
NProgress.done();
/*
causes problems when phonegap mode
*/
},
fastRender:true,
unload: function () {
Session.set("adding_group", true);
Session.set("group_name", false);
Session.set("group_date", false);
Session.set("group_friends", false);
Session.set("group_location", false);
Session.set("group_rules", false);
Session.set("group_desc", false);
Session.set("group_save", false);
},
yieldTemplates: {
'nav': {to: 'header'}
},
data:{
posts:Posts.find({}),
metaTitle:function(){
var one = Posts.findOne({}); //just for the example
return document.title = one.title; //just for the example
}
}
});
this will insert a document.title of the posts if ill do this dynamic path segments
( findOne by ID ) it will return the current post title,
i think ill make this simple thing a package, i haven't seen similar package at atmosphere.
hope it helps you guys.

Related

make the title post clickable vue

I'm using vue + laravel and i try do display the data from api like this:
<div v-for="article in articles" :key="article.id" class="hieght">
<div class="NewArticle">
<h6 class="NewArticleTitle">{{ article.title.ar }}</h6>
</div>
<div>
<p class="NewArticleBody">{{ article.excerpt.ar }}</p>
</div>
</div>
and the script is:
<script>
export default {
data() {
return {
articles: []
}
},
created() {
this.axios
.get('http://localhost:8000/api/articles/')
.then(response => {
this.articles = response.data;
});
}
}
But I want the post to open when I click on the title, I don't know how can i do that using vue
You need to create a view component for your post. and make the h6 title tag a router-link tag that takes you to the post (or article) details page.

Can't get nuxt-link to work when trying to render _slug.vue page with Nuxt, Apollo and WPGraphQL

I have a nuxt/vue app using apollo to query WPGraphQL on Wordpress. Im having hard time setting up my nuxt-link on my index page to route to my _slug.vue page. If I manually enter the url on the browser using the post's slug, I am able to render the data I want. In my index page, how do I use the post.slug with params to get my _slug.vue page to render?
This is my GraphQL Query:
post(id: $slug, idType: SLUG) {
title
slug
date
id
content(format: RENDERED)
author {
node {
firstName
lastName
}
}
}
}
My /blog/index.vue page has the list of blog posts and I am trying to use nuxt-link to link each post to render _slug.vue:
<template>
<div class="blog">
<h1 class="blog__title">Blog</h1>
<nuxt-link
v-for="post in posts.nodes"
:key="post.slug"
:to="'blog/' + { params: { slug: post.slug } }"
class="blog__post"
>
<h3 class="blog__post-title">
{{ post.title }}
</h3>
<div class="blog__post-content" v-html="post.content" />
</nuxt-link>
</div>
</template>
<script>
import getPostByID from '~/apollo/queries/GetPostByID'
export default {
data() {
return {
posts: [],
query: ''
}
},
apollo: {
posts: {
prefetch: true,
query: getPostByID,
update: (data) => data.post
}
}
</script>
With my _slug.vue file below, It uses the same query as my blog page and is able to render if I type the proper url with slug on the browser:
<template>
<article class="post">
<h1>{{ post.title }}</h1>
<div class="blog__post-content" v-html="post.content" />
</article>
</template>
<script>
import GetPostByID from '~/apollo/queries/GetPostById'
export default {
data() {
return {
post: []
}
},
apollo: {
post: {
prefetch: true,
query: GetPostByID,
variables() {
return { slug: this.$route.params.slug }
}
}
}
}
</script>
And what exactly does ".slug" refer to from "this.$route.params.slug"?
If your index page is correctly displaying the list of posts, then you just need to adjust the url slightly.
<nuxt-link
v-for="post in posts.nodes"
:key="post.slug"
:to="'blog/' + { params: { slug: post.slug } }"
class="blog__post"
>
Should be:
<nuxt-link
v-for="post in posts.nodes"
:key="post.slug"
:to="`blog/${post.slug}`"
class="blog__post"
>
this.$route.params.slug refers to the url parameter you named by creating the dynamic file _slug.vue. So if you have pages/blog/_slug.vue and navigate to your-app.com/blog/my-first-post, my-first-post is the parameter string you get back when accessing this.$route.params.slug.
Slug isn’t a magical keyword, it could be anything instead and depends on the file name you create in your blog directory. Given the same url and pages/blog/_unicorn.vue, you would call this.$route.params.unicorn to return my-first-post.

VueJS - template variables not reactive with data variable

I'm making a chat system with socket.io and VueJS, so customers can talk to an admin. But when a client connects to the server, the variable in the data() updates. But the template is not updating.
Here is my code:
<template>
<div>
<div class="chats" id="chat">
<div class="chat" v-for="chat in chats">
<b>{{ chat.clientName }}</b>
<p>ID: {{ chat.clientID }}</p>
<div class="jens-button">
<img src="/icons/chat-bubble.svg">
</div>
</div>
</div>
</div>
</template>
<script>
let io = require('socket.io-client/dist/socket.io.js');
let socket = io('http://127.0.0.1:3000');
export default {
name: 'Chats',
data() {
return {
chats: [],
}
},
mounted() {
this.getClients();
this.updateClients();
},
methods: {
getClients() {
socket.emit('get clients', true);
},
updateClients() {
socket.on('update clients', (clients) => {
this.chats = clients;
console.log(this.chats);
});
}
},
}
</script>
Then I get this, the box is empty:
But I need to get this, this will only appear when I force reload the page. I don't know what I'm doing wrong...
Oke, I've found out where the problem was, in another component I used plain javascript which brokes the whole reactive stuff.

How does vuejs react to component data updated asynchronously

I am very new with vuejs and recently started to try to replace some old jquery code that I have and make it reactive with vuejs. The thing is I have a component that gets information from a nodejs server via socket.io asynchronously.
When I get the data and update my component's data I see the changes when I console log it but it does not change the DOM the way I want it to do.
What is the proper way to grab data asynchronously and use it inside a component? I post some parts of my code so you can see it. I will appreciate any advice you can give me. Thanks in advance!
Vue.component('chat', {
data() {
return {
chat: null,
commands: [],
chatOpened: false,
}
},
props: [
'io',
'messages',
'channels',
'connectChat',
'roomChat',
'user',
'userId',
'soundRoute',
],
methods: {
openChat() {
this.chatOpened = true;
},
closeChat() {
this.chatOpened = false;
},
},
created() {
this.chat = this.$io.connect(this.connectChat);
this.commands.push('clear');
let self = this;
$.each(this.channels, function(index, value) {
self.chat.emit('join', {room: index, user: self.user, userId: self.userId}, function(err, cb) {
if (!err) {
users = cb.users;
messages = cb.messages;
if (messages.length > 0) {
self.channels[index].loaded = true;
}
//some more code
}
});
});
console.log(this.channels);
},
template: `
<div>
<div id="container-chat-open-button" #click="openChat" :class="{hide : chatOpened}">
<div>+90</div>
<i class="fas fa-comment-alt"></i>
</div>
<div id="container-chat" class="chat__container" :class="{open : chatOpened}">
<div id="container-chat-close-button" #click="closeChat">
<span>
<div>
<i class="fas fa-comment-alt"></i>
#{{ messages.chat_lobby_icon_title }}
</div>
<i class="icon-arrowdown"></i>
</span>
</div>
<div id="alert-chat" class="chat__container-notifications animated flash"></div>
<div class="row">
<ul>
<li v-for="channel in channels" v-show="channel.loaded === true">Channel loaded</li>
</ul>
</div>
</div>
</div>
`
});
I would expect to see the list of channels with messsages but instead I don't see the list even thought I see my channels with the loaded attribute set to true (by default they all have this attribute set to false).
My guess is that it's this part that is not working as expected.
if (messages.length > 0) {
self.channels[index].loaded = true;
}
The reactive way of doing this is by setting the full object again.
Vue.set(self.channels, index, {
...self.channels[index],
loaded: true
}
EDIT 1:
this.channels.forEach((channel) => {
this.chat.emit('join', {room: index, user: self.user, userId: self.userId}, (err, cb) => {
if (!err) {
users = cb.users;
messages = cb.messages;
if (messages.length > 0) {
Vue.set(self.channels, index, {
...self.channels[index],
loaded: true
}
}
//some more code
}
});
})
You'll need to add support for the rest-spread-operator using babel.

How to pass Sql row data to Vue file (Laravel Project)

i'm trying to pass a data and use it inside Vue file but i cant get it to work here's my code
<template>
<div class="row profile-container">
<div class="col-sm-4">
<img src="/img/default.jpg" alt="" class="profile-img">
</div>
<div class="col-lg">
<h5>{{$user->name}}</h5>
<div class="card w-100">
<ul class="list-group list-group-flush">
<li class="list-group-item">Cras justo odio</li>
<li class="list-group-item">Dapibus ac facilisis in</li>
<li class="list-group-item">Vestibulum at eros</li>
</ul>
</div>
</div>
</div>
</template>
Here's the profile controller which returns to profile with data
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
class ProfileController extends Controller
{
public function index($id)
{
$user = User::where('unique_id', $id)->firstOrFail();
return view('pages.profile')->with('user', $user);
}
}
Here's the app.js
require('./bootstrap');
window.Vue = require('vue');
Vue.component('welcome', require('./components/Welcome.vue').default);
Vue.component('profile', require('./components/Profile.vue').default);
const app = new Vue({
el: '#app'
});
Routes
Route::get('/', 'PagesController#index' );
Auth::routes();
Route::get('/logout', '\App\Http\Controllers\Auth\LoginController#logout');
Route::get('/profile/{id}', 'ProfileController#index');
Here's the blade file pip didly doo i dont know what to write anymore it lookslikemy post is mostly code so ill just add some details here, thatsprettycoolshaggyisgod i dont know what else to add here please send help
#extends('layouts.master')
#section('title')
<title>Profile</title>
#endsection
#section('content')
#if(Auth::user()->type==='user')
<profile></profile>
#elseif (Auth::user()->type==='admin')
<h1>Hi Admin</h1>
#endif
#endsection
your script should look something like this:
<script>
export default {
name: 'profile',
data() {
return {
user: []
}
},
methods: {
getUser() {
let _this = this;
axios.get('/user')
.then(function (response) {
_this.user = response.data;
}).catch(function (error) {
console.log(error);
});
},
created() {
this.getUser();
}
}
</script>
add this to your routes file:
Route::get('/brands', function($id) {
$user = User::where('unique_id', $id)->findOrFail();
return view('pages.profile')->with('user',$user);
});
let me know if that helps, i think you've missed out a lot of code, it's not as easy as passing data through to a Laravel view, but hopefully that gets you started