Render router's template to dynamic point in DOM - meteor

I wanna render show template into index template right after clicked element.
Some code(jade):
template(name="index")
ul
for post in posts
li
a(href="posts/1")= post.title
// render full post #1 here if link clicked
li
a(href="posts/2")= post.title
// render full post #2 here if link clicked
li
a(href="posts/3")= post.title
// render full post #3 here if link clicked
So I don't need to replace whole index template when user clicks show post link. I just need render show template right after link to this post.
Also I need to show only one post at same time, so if user clicks one post, then another, first one should be removed from DOM and second one should be rendered just in his place (right after show link).
How can I do that with meteor and Iron Router?

See Blaze.render or Blaze.renderWithData
Insert placeholders into your markup:
template(name="index")
ul
for post in posts
li
a(href="posts/1")= post.title
div(id="post1") // render full post #1 here if link clicked
li
a(href="posts/2")= post.title
div(id="post2") // render full post #2 here if link clicked
li
a(href="posts/3")= post.title
div(id="post3") // render full post #3 here if link clicked
Then setup your helpers:
Template.index.helpers({
'click a': function(ev){
... determine which link was clicked on
... pick the node to inject ex:
var node = $('#post2');
Blaze.render('postTemplate',node);
}
});

One way to do this would be to go ahead and render everything, but keep it hidden. Then you can add a click event handler that hides everything and shows only the thing that was clicked:
<template name='index'>
<ul>
{{#each posts}}
<li>
<a href='#' class='show-index-link' _id="{{_id}}"><!--Store _id so we can retrieve it in event handler-->
<div class='post-show-hide' id='post-show-hide-{{_id}}' style='display: none;'><!-- make it easy to select in the event handler-->
{{> post}}<!-- data context is the post in question -->
</div>
</li>
{{/each}}
</ul>
</template>
Then your event handler might look something like this:
Template.index.events({
'click .show-index-link': function(event) {
var _id = $(event.currentTarget).attr('_id'); // grab the ID of the post to show
event.preventDefault();
$('.post-show-hide').hide(); // hide all of them
$('#post-show-hide-' + _id).show(); // Show only the one we just clicked on
}
});
This seems the most straightforward way to accomplish this to me, but if you're concerned about the performance of sending all of the posts to the client, you could also consider having an event handler that subscribes to the post in question. That seems significantly more difficult (and if you're really worried about that sort of performance issue, you can get around it much more easily, e.g. with pagination), so unless you really need it, I'd stick to something simple like the solution above.

Related

Display json local

I have been trying to display JSON data from one page to another on click.
For example, a user clicks on an image and it passes the same image/text to another page.
Here is my code
ygt.js
<h2 class="pet-name">${pet.name}
<h1 class="species">${pet.species}
</div>
<div></div></div>
</div>
</div>
`;
}
document.getElementById("app").innerHTML = `
<h1 class="app-title">Kids
${petsData.map(petTemplate).join("")}
`;
You can use localStorage to pass the values from one page to another. Let's say you have the books in one page and you want to pass the book name to another page.
In your books page, you can add a function like this:
function saveBook(bookName, link){
localStorage.setItem("bookName", bookName):
window.location.href = link
}
Then you can call this function in your onclick event.
<div class="olay" onclick="saveBook('The Book','${pet.href}');" style="cursor: pointer;">
When someone clicks on the book, it will save the value in the localStorage and redirect to the page you need.
In the second page, you can use a function to retrieve the saved value:
var bookName = localStorage.getItem('bookName');
More info on localStorage : https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage

Cascading dropdowns on Mediawiki site

This is my first post here. I am not a developer but have learned a bit about CSS the last few months. I have a basic Mediawiki site which has raw HTML enabled on the site which is a secure site and only a very limited number of users with edit privilege's.
I am trying to make it so that when a user clicks the "Submit" button on the HTML form for the cascading dropdown, it will take them to a specific section on a page, based on what they have chosen in all the drop down boxes. I have used the w3schools site to borrow some code snippets.
Here is my form:
<html>
<form name="form1" id="form1" action="Front-end#CSS#Backgrounds">
Subjects: <select name="subject" id="subject">
<option value="" selected="selected">Select subject</option>
</select>
<br><br>
Topics: <select name="topic" id="topic">
<option value="" selected="selected">Please select subject first</option>
</select>
<br><br>
Chapters: <select name="chapter" id="chapter">
<option value="" selected="selected">Please select topic first</option>
</select>
<br><br>
<input type="submit" value="Submit">
</form>
</html>
And here is the java script I am using.
var subjectObject = {
"Front-end": {
"HTML": ["Links", "Images", "Tables", "Lists"],
"CSS": ["Borders", "Margins", "Backgrounds", "Float"],
"JavaScript": ["Variables", "Operators", "Functions", "Conditions"]
},
"Back-end": {
"PHP": ["Variables", "Strings", "Arrays"],
"SQL": ["SELECT", "UPDATE", "DELETE"]
}
}
window.onload = function() {
var subjectSel = document.getElementById("subject");
var topicSel = document.getElementById("topic");
var chapterSel = document.getElementById("chapter");
for (var x in subjectObject) {
subjectSel.options[subjectSel.options.length] = new Option(x, x);
}
subjectSel.onchange = function() {
//display correct values
for (var y in subjectObject[this.value]) {
topicSel.options[topicSel.options.length] = new Option(y, y);
}
}
topicSel.onchange = function() {
//display correct values
var z = subjectObject[subjectSel.value][this.value];
for (var i = 0; i < z.length; i++) {
chapterSel.options[chapterSel.options.length] = new Option(z[i], z[i]);
}
}
}
In my form example above I hard coded the action= portion to say Front-end#CSS#Backgrounds
When I click the submit button it launches or takes me to this URL:
https://mysitename.com/myenvironment/index.php/Front-end?subject=Front-end&topic=CSS&chapter=Backgrounds#CSS#Backgrounds
In the example subject = my page name, in this case Front-end, topic = my Heading 1 section, in my case CSS, and chapter = my Heading 2 section, in my case Backgrounds.
But it's not working fully. When I click submit it takes me to the "Front-end" page on my Mediawiki site but it doesn't recognize or do anything with the Heading 1 and Heading 2 parts.
The way this will be used is to allow the user to select the page and section of a page they will be going to. So that in a form using three cascading dropdowns, the user will first pick the subject, which is actually the name of the page on my Mediawiki site, the second drop down will be the Heading 1 section, and the third drop down will be the Heading 2 section which is where I want the user to end up on the page.
The Mediawiki page sort of looks like this:
Page name is "Front-end"
Table of contents is for example:
## CSS ##
### Borders ###
### Margins ###
### Backgrounds ###
### Float ###
I will have the HTML cascading dropdown forms setup with three boxes. In my example, the user picks Front-end -- CSS -- Backgrounds and when they hit submit they go directly to the Heading 2 section on my page for "Backgrounds" Obviously, I need to code it so that whatever combination the user picks I take them to the right page section.
Any ideas on how I can do this? I would like to stick with the simple HTML form and Java Script example above as it is easy for me. Any advice is appreciated! Thanks in advance and sorry for the long post.
GJ231
Well many things to check.. First of all.. https://mysitename.com/myenvironment/index.php/Front-end?subject=Front-end&topic=CSS&chapter=Backgrounds#CSS#Backgrounds
An url can jump to one Anchor. not two. So am I guessing you will need some more JavaScript on checking the Post url and figure out where to go to on the page depending on the Post url.
The content of the page would need to have Anchor links inside them, something like #-- e.g. #Front-End-CSS-Backgrounds
Then before you post, you should change the url to something like : https://mysitename.com/myenvironment/index.php/Front-end#Front-End-CSS-Backgrounds
That will bring the person to the right spot.
If you cannot create anchor links on the page, perhaps you can create divs with the same format Id's ? or Something similar. Then have JavaScript jump to the relevant ID based on the url.

Show specific menu only on one page

I've navigation menu and I would like to display the helper menu button only when the user is on specific page and be hided on others.
I've tried this way, but that doest worked
{{#if Store}}
Filters
{{/if}}
Can you please suggest how achieve this function?
in your template helper, you can lookup the route name with
Router.current().route.getName()
then you can set a helper variable to lookup if you are on this page.
Template.mytemplate.helpers({
'Store': function() {
return Router.current().route.getName() == 'Store'; //the Route name
}
});
then use the Store variable in your template as you did.

Using a custom javascript script file with durandal template

I work on a Visual Studio 2012 MVC4 Project with the Durandal template. In this template, the shell.js page gives us a quite simple menu solution where every elements are located on top. Personally I need something different. For that purpose, I have a javascript file named dropdown.js which allows me to show/hide sub menus. It works pretty well in a standard project but I was not able to do it working with the durandal template.
Here is what I try:
I added a reference to the dropdown.js script in the Index.chtml:
<script src="~/Scripts/dropdown.js"></script>
Then in the shell.html page, I would like to use it like this:
<li class="dropdown" data-role="dropdown">
...
...
</li>
Here is a little portion of the dropdown.js:
$(function () {
alert('XXXX');
$('[data-role="dropdown"]').each(function () {
alert('YYYY');
$(this).Dropdown();
})
})
As you can see, each element decorated with the 'dropdown' class should have been catched. It doesn't work with durandal. I placed some alert boxes to check it. The alert 'XX' is showed but the alert 'YY' is never showed.
I searched a bunch of hours without success.
Any idea?
Check out the life cycle events tha tyou can tap into for Durandal here
viewAttached may help since you can tap into when the view and dom are ready.
I think the problem is that when the dropdown.js function is executed before the menu renders and because of that the jquery selector doesn't catch any list item.
I think that your best option is to make a knockout binding to transform your list items in dropdowns.
The binding would look something like:
ko.bindingHandlers.dropdown= {
init: function (element, valueAccessor, allBindingsAccessor) {
$(element).Dropdown();
},
update: function (element, valueAccessor) {
}
};
And in the view:
<li class="dropdown" data-bind="dropdown : {}">
...
...
</li>

What is the proper way to manipulate template instance in Meteor framework?

I am new to Meteor and wondering how to solve what seems to me is a common problem.
Let's say I have a handlebars template listing restaurants:
<template name="Restaurants">
{{#each Restaurant}}
{{name}}
{{/each}}
</template>
Now when user clicks on a restaurant template I want to display a menu for that restaurant.
I added a subtemplate named "menuItems" that contains all menu items for a given restaurant:
<template name="Restaurants">
{{#each Restaurant}}
{{name}}
{{> menuItems}}
{{/each}}
</template>
I want to render only one instance of menuItems subtemplate when user clicks anywhere on Restaurant template (render only the menu items for the selected restaurant).
It should go something like:
Template.Restaurants.events({
'click' : function (e) {
// This is where I need help - what's the right way to display only one subtemplate instance?
}
});
My question is - how I can select and display only the correct menuItems template instance?
Also I would like to place menuItems template instance in DOM only after the click and not before (having all the menu items for all restaurants and only hiding those divs is not an option because of high number of those items in db).
If you think I should approach the solution in some other way please let me know, thanks!
You should use {{#if}} and Session. Like this:
<template name="Restaurants">
{{#each Restaurant}}
{{name}}
{{#if restaurantSelected}}
{{> menuItems}}
{{/if}}
{{/each}}
</template>
By using Session, a reactive data source, you can set a global flag indicating whether a restaurant is selected.
Template.Restaurants.restaurantSelected = function() {
// check whether this restaurant is selected. "this" refers to the current
// context, eg. the current restaurant in the loop
return Session.equals("restaurantSelected", this._id);
}
Whenever you change that session key, the value will update and the template will be redrawn. So, you can toggle it when clicking a restaurant:
Template.Restaurants.events({
'click' : function (e) {
// store the current restaurant ID
// make sure the event selector is correct!
Session.set("restaurantSelected", this._id);
}
});
Edit For clarity's sake I created a complete example that you can copy into your project and try out.
I almost always avoid Session. I think it pollutes the global scope. Also it prevents you from running multiple instances of the template. I recommend using a reactiveVar or reactiveDict scoped to the template instance. Thanks to Rahul for starting a demo project. I took his example and modified it to show my recommended approach.
attach a reactiveDict to the template instance onCreate. Use this to store state instead of global Session var!
Template.Restaurants.onCreated(function() {
this.state = new ReactiveDict;
this.state.set('currentRestaurant', null); // could set a init value here
});
this event handler will set the state of the reactiveDict on click
'click': function(e, t) {
t.state.set('currentRestaurant', this._id);
}
this helper is used to show/hide the menu template
currentRestaurant: function() {
// check whether this restaurant is selected. "this" refers to the current
// context, eg. the current restaurant in the loop
return Template.instance().state.equals("currentRestaurant", this._id);
},
menu template receives the selected id from data context instead of from Session
<template name="Restaurants">
<ul>
{{#each Restaurant}}
<li>
{{name}}
{{#if currentRestaurant}}
{{> menuItems restaurant=_id}}
{{/if}}
</li>
{{/each}}
</ul>
</template>
<template name="menuItems">
<ul>
<li class="menu">I'm a menu for {{restaurantName}}!</li>
</ul>
</template>
added this helper just to show we really got the id
Template.menuItems.helpers({
restaurantName: function() {
var restaurantMenu = Restaurants.findOne(this.restaurant);
return restaurantMenu.name;
},
})
Posted a fully working project to github.
https://github.com/white-rabbit-japan/scopedReactivityDemo
App is hosted on meteor.com
http://scopedreactitivydemo.meteor.com/

Resources