Meteor: How to make two views - listing and article - javascript

What would be the best way in meteor for creating a template for using two different views? Let's call the template 'article' and by default there should be a list of all articles with an input field to create/add new elements. When selecting an article, the selected one should be displayed.
So right now what I am trying is this:
package.js:
Package.onUse(function(api){
api.versionsFrom("METEOR#1.1.0.3");
api.addFiles([
'lib/client/templates/article.html',
], ['client']);
});
router.js:
Router.route('/article/:_id?', {
name: 'article'
})
templates/article.html:
<template name="article">
<form><input name="createNewArticle" type="text"></form>
<ul><li>List of articles</li></ul>
</template>
<template name="article_detail">
<p>Content of article</p>
</template>

If you wish to redirect to a new page, make sure you have two separate routes (one for the list of all articles and another for the the single article or article detail)
lib/router.js
Router.route('/articles', {
name: 'articles',
waitOn: function () {
return [
Meteor.subscribe('articles'),
];
},
data: function() {
return {
articles: Articles.find({})
}
}
});
Router.route('/article/:_id', {
name: 'article',
template: 'article',
waitOn: function () {
return [
Meteor.subscribe('article', this.params._id),
];
},
data: function () {
return {
article: Articles.findOne({
_id: this.params._id
})
};
}
});
client/templates/article.html:
<template name="articles">
<form><input name="createNewArticle" type="text"></form>
<ul>
{{#each articles}}
<li>{{title}}</li>
{{/each}}
</ul>
</template>
<template name="article">
<p>{{title}}</p>
</template>
Make sure you setup your publications too in server/publications.js

Related

how can I reference a method from the same component in the data of the component vue js

I have the following component
<template>
<li v-for="(item, i) in this.menu" :key="i" #click="item.action()"> //trying to call the method in the component
{{menu.title}}
<li>
</template>
<script>
export default {
data: () => ({
menu: [
{title: 'Start Preparing', action: this.startPrepare}, //how do I reference the method here?
{title: 'Cancel Order'},
],
}),
methods: {
startPrepare: function (orderId) {
console.log("start")
}
}
}
</script>
As you can see in the commented sections, I have a menu in the data section, it has a title and action properties in it. So in the template, I want to invoke whatever function we have specified when someone clicks on that particular item.
So how do I refer a method in the same component in the data section of that component? as of now, I am getting start prepare is undefined error.
Let me know if any further clarifications are needed
The main problem here I think is that you're using an arrow function for your data, which can't be bound to the Vue instance. You need to use a normal function instead ..
export default {
data() {
return {
menu: [{
title: 'Start Preparing',
action: this.startPrepare
}, //how do I reference the method here?
{
title: 'Cancel Order'
},
],
}
},
methods: {
startPrepare: function(orderId) {
console.log("start")
}
}
}
<template>
<li v-for="(item, i) in this.menu" :key="i" #click="item.action()"> //trying to call the method in the component
{{menu.title}}
<li>
</template>
Try to add the method name as a string like action value and in the template access it like #click="handleAction(item.action)":
<template>
<li v-for="(item, i) in menu" :key="i" #click="handleAction(item.action)">
{{menu.title}}
<li>
</template>
<script>
export default {
data: () => ({
menu: [
{title: 'Start Preparing', action:'startPrepare'}, //how do I reference the method here?
{title: 'Cancel Order'},
],
}),
methods: {
handleAction(actionName){
this[actionName]();
}
startPrepare: function (orderId) {
console.log("start")
}
}
}
</script>

VueJS2 how to dynamically emit event to parent component?

just like the title i need to dynamically emit an event to parent component's methods, i have a component structured like this
<TableComponent
:actionmenus="actionmenus"
#edit="parenteditmethod"
#delete="parentdeletemethod">
</TableComponent>
here is actionmenus object
actionmenus: [
{title: 'Edit', emitevent: 'edit'},
{title: 'Delete', emitevent: 'delete'}
]
and then here is snippet of my tablecomponent
...
<ul>
<li v-for="menu in actionmenus"><a #click="$emit(menu.emitevent)" class="text-menu">{{ menu.title }}</a></li>
</ul>
...
i know this should be easily done by $emit('edit') or $emit('delete') without using actionmenus object but the $emit() part should be dynamic based on the passed array actionmenus so that the tablecomponent can be re-used on different case. how should i approaching this? is there any way?
From what I understand, you would like to emit an event from the child component to the parent, and pass some data with the emit (sorry if thats not the case).
As you know, you can emit events in the child component like this :
$emit("EVENT");
And Catch it in the parent like this :
<childTag v-on:EVENT="parentFunction"></childTag>
You can also pass data to the parent from the child like this :
$emit("EVENT",DATA);
And catch the data in the parent function like this
<childTag v-on:EVENT="parentFunction"></childTag>
...
methods{
parentFunction(DATA){
//Handle the DATA object from the child
}
}
Hope this helps and best of luck!
#codincat is right, that it all works. It's true also for Vue3
const rootComponent = {
el: "#app",
data: function () {
return {
actionmenus: [
{ title: "Edit", emitevent: "edit" },
{ title: "Delete", emitevent: "delete" }
]
};
},
methods: {
parenteditmethod() {
console.log("edit");
},
parentdeletemethod() {
console.log("delete");
}
}
};
const app = Vue.createApp(rootComponent);
app.component("table-component", {
props: { actionmenus: Array },
template: `
<ul>
<li v-for="menu in actionmenus">
<a #click="$emit(menu.emitevent)" class="text-menu">{{ menu.title }}</a>
</li>
</ul>`
});
const rootComponentInstance = app.mount("#app");
<!-- https://stackoverflow.com/questions/43750969/vuejs2-how-to-dynamically-emit-event-to-parent-component -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.29/vue.global.min.js"></script>
<div id="app">
<table-component :actionmenus="actionmenus" #edit="parenteditmethod" #delete="parentdeletemethod">
</table-component>
</div>

meteor template: parse html content

I saved some HTML-content in my collection. By using IronRouter data() will be used to set the cursor/array. In this example I just show an example array.
Now the HTML-content isn't shown correctly, as it doesn't get parsed. The user would see the HTML-tags. What do I have to do to get the content displayed correctly?
IronRouter
Router.route('/article/:_id', {
name: 'article',
data: function () {
var articles = [{ title: 'title', content: '<strong>content</strong>'}];
return { articles: articles };
}
});
template
<template name="article">
{{#each articles}}
<h1>{{title}}</h1>
<section>{{content}}</section>
{{/each}}
</template>
Use Handlebars triple-stash:
<template name="article">
{{#each articles}}
<h1>{{title}}</h1>
<section>{{{description}}}</section>
{{/each}}
</template>

How to iterate through all existing users in a Meteor template?

I am trying to get all the users to be iterated on my home page template, but I'm having troubles getting it to work. I've been trying so many different techniques but this is what I've got now:
Server:
Meteor.publish('userList', function() {
return Meteor.users.find({}, {fields: {username: 1, emails: 1, profile: 1}});
});
Routing:
Router.route('/', {
name: 'home',
template: 'home',
waitOn: function() {
return Meteor.subscribe('userList');
},
data: function() {
return Meteor.users.find({});
}
});
HTML:
<template name="home">
<h1>Home page</h1>
{{#each userList}}
<p>Test</p>
{{userList.username}}
{{/each}}
</template>
I think my problem actually lies in the {{#each}} block because I don't know what to call there. Not even the test text displays.
One way to solve your problem is to return {userList: Meteor.users.find()} in your data function:
Router.route('/', {
name: 'home',
template: 'home',
waitOn: function() {
return Meteor.subscribe('userList');
},
data: function() {
return {userList: Meteor.users.find()};
}
});
Then, you could iterate through userList by changing your home template to:
<template name="home">
<h1>Home page</h1>
{{#each userList}}
<p>Test</p>
{{username}}
{{/each}}
</template>

How render a route relevant subheader with meteor blaze?

The end result of all of what I am about to go over is the subheader is not rendering on screen like i want it to.
Currently there is a mongo collection subheader with a category field and a texth field.
Subheader = new Mongo.Collection('subheader');
Meteor.methods({
subheaderInsert: function(subheaderIdAttributes) {
check(String);
check(subheaderIdAttributes, {
texth: String,
category: String
});
var subheaderId = _.extend(postAttributes, {
submitted: new Date()
});
var subheaderId = SubheaderId.insert(subheader);
return {
_id: subheaderId
};
}
});
There is a route that subscribes to the subheader and other page data.
Router.route('/', {
name: 'home',
controller: MissionstatementpostController,
waitOn:function () {
return Meteor.subscribe('subheader', 'home');
}
});
The publish function appears to work fine.
Meteor.publish('subheader', function(cat) {
return Subheader.find({category: cat});
});
The correct doc from the mongodb collection is reaching the client. this can be seen by
Subheader.findOne(); output Object {_id: "NPo5cwqgjYY6i9rtx", texth: "ex text", category: "home"}
The problem starts here
The template loaded by the Controller in this case MissionstatementpostController is postlist
<template name="postsList">
<div class="posts page">
{{> subheader}}
<div class="wrapper">
{{#each posts}}
{{> postItem}}
{{/each}}
</div>
{{#if nextPath}}
<a class="load-more" href="{{nextPath}}">Load more</a>
{{else}}
{{#unless ready}}
{{> spinner}}
{{/unless}}
{{/if}}
</div>
</template>
Here is the subheader template
<template name="subheader">
<div class="container">
<p>{{{texth}}}</p>
</div>
</template>
So what did I mess-up?
thanks
you must create a template helper for your subheader template. To return just the texth field, the helper will be like this.
Template.subheader.helpers({
texth: function() {
var sh = Subheader.findOne();
return sh && sh.texth;
}
});
You can return the whole document and use the #with helper inside the template.
Template.subheader.helpers({
subh: function() {
return Subheader.findOne();
}
});
<template name="subheader">
{{#with subh}}
<div class="container">
<p>{{{texth}}}</p>
</div>
{{/with}}
</template>
You can find more info about template helpers on Meteor Docs.

Categories