How to use client side javascript variables as array index? - javascript

So I'm trying to teach myself to make a website. I'm using node and expressJS server side to send the template to the client like this.
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res) {
var cityData = require("../public/cityData/paris.json");
res.render('index', {
cityData : cityData
});
});
module.exports = router;
In this case I'm just passing a JSON file with information about the city of Paris that I want to display to the client. It has an array of image URLs that I can use for pictures. My issue is that I only want to show one image at a time and change the image to the next one when a key is pressed (or a button if necessary, but preference for key).
My issue comes on the client side, I can get the JSON object and generate the page based on it if I use a value eg [0] in the place of the "index" variable, but if I have it setup as shown, index is "undefined". So my question is, how does one make a variable that will exist clientside and allow me to rerender the page with a new picture, is that even possible? I've been reading stack overflow for hours and nothing seems to be what I want.
Thanks.
HTML code --->
<% include templates/head.ejs %>
<script "text/javascript" >
var index = 0;
</script>
<body>
<!-- This imports the naviagtion template I made -->
<% include templates/navigation.ejs %>
<div id="wrapper">
<% include templates/sidebar.ejs %>
<!-- Page Content -->
<div id = "page-content-wrapper">
<div class="container-fluid">
<!-- This imports an image -->
<div class = "row">
<div class = "text-center">
<img id = "imgArea" src = <%- cityData.imageUrl[index] %> class = "img-rounded col-xs-12 col-md-6" width = "device-width">
</div>
</div>
</div>
</div>
</div>
<!-- Menu Toggle Script -->
<script>
$("#menu-toggle").click( function(e) {
e.preventDefault();
$("#wrapper").toggleClass("menuDisplayed");
});
$(document).keydown(function(e){
index ++;
document.getElementById("imgArea").innerHTML = cityData.imageURL[index];
});
</script>
</body>

EJS runs on the server. It's the server who renders the webpage and then the variable is lost on the client. I would recommend a for loop to include all images when you render the index.ejs BUT put a class of hidden on all images except the first one. Then using some front-end javascript magic you can view images side by side. You can use jquery/bootstrap for that. ( Bootstrap carousel is a nice example ).
In order to store variables in the front-end you can use this:
<script>
var frontEndVar = <%= EJSvar %>;
</script>
Some times this will simply evaluate to [object Object] so you might want to first use JSON.stringify on the server side

Related

How to Change links in node.js

i've been trying for a while to get the tabs on my navigation bar to change (including the link) when a user logs in. The whole thing is a problem on the index page, as you should enter it both logged in and not logged in. i have a in my navigation bar where all tabs are listed via an anchor. This is my app.get of the index:
app.get('/', (req, res)=>{
const {userId} = req.session;
if(userId==undefined){
res.render('index');
}
else{
res.render('index');
}
});
and this Is my header :
<nav>
<div class="logo">Logo</div>
<div class="openMenu"><i class="fa fa-bars"></i></div>
<ul class="mainMenu">
<li>Startseite</li>
<li>Anmelden</li>
<li>Registrieren</li>
<li>Impressum</li>
</ul>
<div class="closeMenu"><i class="fa fa-times"></i></div>
</nav>
I want to change "Anmelden" to "Log out" with this :
<li><form id="abmelden" method="POST" action="/logout">Abmelden</form></li>
And I want to change "Registrieren" to "Dashboard" therefore the link of the a tag and the text must be changed.
Is there a way, where I can use a command like res.send() but to send the depends on, if the user is logged or not
One common technique is to dynamically insert a class on the body tag that is either loggedIn or notLoggedIn. You can then control the rest of your page purely with CSS.
You just insert both the loggedIn and not loggedIn tabs in your navbar and use CSS so one of them is always hidden based on what class is in the tag:
<body class="loggedIn">
or
<body class="notLoggedIn">
Then, you use the same page for both, but use CSS to hide/show things based on the state in the tag. You use conditionals in EJS to insert the right class for the tag based on the logged in state.
You can do this in your index.html page with an EJS conditional to dynamically construct the <body> tag with the right class in it:
<body
<% if (loggedIn) { %>
class="loggedIn" >
<%} else { %>
class="loggedOut" >
<% } %>
I'm not an expert on EJS so if this isn't perfect EJS syntax, you can hopefully see the concept here. When you render your template, you need to pass the loggedIn boolean to the rendering engine so it can dynamically adjust based on that.
Then, you add CSS that shows or hides:
/* hide/show based on login status */
.loggedIn .whenLoggedIn, .loggedOut .whenLoggedOut {display: block;}
.loggedOut .whenLoggedIn, .loggedIn .whenLoggedOut {display: none;}
Then, you put both tabs in your navbar and the class in the <body> tag combined with your CSS will hide/show one of them
<nav>
<div class="logo">Logo</div>
<div class="openMenu"><i class="fa fa-bars"></i></div>
<ul class="mainMenu">
<li>Startseite</li>
<li class="whenLoggedOut">Anmelden</li>
<li class="whenLoggedIn">Ausloggen</li>
<li>Registrieren</li>
<li>Impressum</li>
</ul>
<div class="closeMenu"><i class="fa fa-times"></i></div>
</nav>
Note: You could also use EJS conditionals to just generate the desired tab also so just one tab was generated. But, the technique shown here creates one EJS conditional and then everything else is just HTML/CSS which some people find to be simpler to manage. So, you could have multiple places in the page that have loggedIn and notLoggedIn HTML, but they all work off the class/CSS generates from the one EJS conditional.
By "tab" you mean changing the html page title ?
it's done with this (add it in your template) :
<html>
<head>
<title>title of the doc</title>
</head>
...
</html>
you can add if statements in your template to adapt things.
But it depends of the templating engine you choosed
for twig its done like that :
{% if userId %} <h1>im logged as user {{userId}}</h1> {% endif %}
dont forget to add userId in the render part like so
res.render('index', {userId});
In your code you first check if the user is logged in with:
if(userId==undefined){
If userID is undefined, that means the user is not logged in, so you send them index.js:
res.render('index');
Then you have an else statement for if the user is logged in, but in your else statement you send the exact same thing as you did for a non-logged in user:
else{ res.render('index'); }
So if you want a different menu for a logged-in user you probably need to send them different html.

Python Flask Web App Navigation Without Page Refresh

I Want to develop a flask navigation bar like Google Contacts.
I Want to Render a particular HTML page inside the red box (as in the picture) when I click each of the navigation buttons (the green box as in picture) without refreshing the page.
I have already tried using
{% extends "layout.html" %}
As #Klaus D. mentioned in the comments section, what you want to achieve can be done using Javascript only. Maybe your question were
How can I send a request to my server-side (to get or fetch some information) and receive back a response on the client-side without having to refresh the page unlike the POST method usually does?
I will try to address the aforementioned question because that's probably your case.
A potential solution
Use Ajax for this. Build a function that sends a payload with certain information to the server and once you receive back the response you use that data to dynamically modify the part of the web-page you desire to modify.
Let's first build the right context for the problem. Let's assume you want to filter some projects by their category and you let the user decide. That's the idea of AJAX, the user can send and retrieve data from a server asynchronously.
HTML (div to be modified)
<div class="row" id="construction-projects"></div>
Javascript (Client-side)
$.post('/search_pill', {
category: category, // <---- This is the info payload you send to the server.
}).done(function(data){ // <!--- This is a callback that is being called after the server finished with the request.
// Here you dynamically change parts of your content, in this case we modify the construction-projects container.
$('#construction-projects').html(data.result.map(item => `
<div class="col-md-4">
<div class="card card-plain card-blog">
<div class="card-body">
<h6 class="card-category text-info">${category}</h6>
<h4 class="card-title">
${item.title_intro.substring(0, 40)}...
</h4>
<p class="card-description">
${item.description_intro.substring(0, 80)}... <br>
Read More
</p>
</div>
</div>
</div>
`))
}).fail(function(){
console.log('error') // <!---- This is the callback being called if there are Internal Server problems.
});
}
Build a function that will fetch the current page via ajax, but not the whole page, just the div in question from the server. The data will then (again via jQuery) be put inside the same div in question and replace old content with new one.
Flask (Server-side)
''' Ajax path for filtering between project Categories. '''
#bp.route('/search_pill', methods=['POST'])
def search_pill():
category = request.form['category']
current_page = int(request.form['current_page'])
## Search in your database and send back the serialized object.
return jsonify(result = [p.serialize() for p in project_list])
Thank you #CaffeinatedCod3r,#Klaus D and #newbie99 for your answers.
I Figured it out. instead of using Flask we can use Angular JS Routing for navigation.
Here is the example that i referred:
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular-route.js"></script>
<head>
<base href="/">
</head>
<body ng-app="myApp">
<p>Main</p>
Banana
Tomato
<p>Click on the links to change the content.</p>
<p>Use the "otherwise" method to define what to display when none of the links are clicked.</p>
<div ng-view></div>
<script>
var app = angular.module("myApp", ["ngRoute"]);
app.config(function($routeProvider, $locationProvider) {
$routeProvider
.when("/banana", {
template : "<h1>Banana</h1><p>Bananas contain around 75% water.</p>"
})
.when("/tomato", {
template : "<h1>Tomato</h1><p>Tomatoes contain around 95% water.</p>"
})
.otherwise({
template : "<h1>Nothing</h1><p>Nothing has been selected</p>"
});
$locationProvider.html5Mode(true);
});
</script>
</body>
</html>
By Using $locationProvider.html5Mode(true) i was able to remove the # from the URL.

How can I add javascript to only a single view in Rails 5?

I have a single controller that has 2 actions/views and a channel all of which have been scaffolded and pretty much using a default project.
When I load either view I can see that the channel subscribes properly.
I need the subscription to happen only on one of the views. Currently the asset pipeline appears to be compiling everything into a single js file and then serving that js file to every page.
When I scaffolded my channel it created some javascript called channel.js. How can I include channel.js with only specific actions/views?
The asset pipeline indeed compiles everything into a single JS file, so there is no built-in way to limit the execution of certain JavaScript files to specific actions.
There is a way to solve this, however. First, add this helper method to application_helper.rb:
# application_helper.rb
def body_classes(*args)
return (#body_classes || []).join(" ") if args.empty?
#body_classes ||= []
#body_classes += args.map { |klass| klass.to_s.gsub("_", "-") }
#body_classes.uniq!
nil
end
And use it in your layout:
<!-- application.html.erb -->
<body class="<%= body_classes %>">
<!-- ... -->
</body>
With this, you can specify certain body classes in your templates, to be added to the <body> tag:
<!-- your_action.html.erb -->
<%= body_classes :my_custom, :action_class %>
<h1>Your action</h1>
<!-- ... -->
The code above will add the following classes to <body>:
<body class="my-custom action-class">
Finally, you can test for these body classes in your JS code:
// your_action.js
if($("body").hasClass("my-custom")) {
// run code specific to pages with the 'my-custom' class
}
Try going into your controller that holds the method to the view you want to have the javascript incorporated in and write this inside:
def 'the view you want to effect' # This could be "index" for your index.html.erb view
#java = "channel.js"
end
Then in the following file, locate your <%= javascript_include_tag %>
views > layout > application.html.erb
Include this into your tag to load a different javascript file for any view you want with the previous process. (Try it with CSS inside your CSS include tags too.)
<%= javascript_include_tag '#{#java}' %>

javascript get value of Mongo field already rendered - Meteor

Hey everyone, thank you very much for your help. Question is edited per suggestions in the comments.
I'm new to Mongo and Meteor.
I have a collection "posts" with a field "slug".
The "post" template is populating correctly with each post's values. Slug value is always something like "my-great-post".
I need to get the text value for the _id's slug, which will be different each time the template is accessed, encode it, write a string, and spit the string back out into the template.
Things tried
can't return a value for "this.slug" or "this.data.slug" in either template helpers or onRendered, even though collection is defined and correctly populating spacebars values in the template
"this" returns "[object Object]" to console.log
app crashes when I try to javascript encode and deliver a string from the helper, probably I don't fully understand helper syntax from the documentation
(I followed advice in the comments to avoid trying to create scripts in the template html, so below is more information requested by everyone helping on this thread)
- Template html -
{{#with post}}
<div class="blog-article">
<div class="blog-header">
<div class="left">
<!-- title -->
<h1 class="post-title">{{title}}</h1>
<div class="holder">
<div class="post-tags">
<!-- tags -->
{{#each tags}}
<span>{{this}}</span>
{{/each}}
</div>
</div>
</div>
</div>
<div class="blog-post">
<div class="blog-copy">
<!-- date -->
<div class="post-date">{{post_date}}</div>
<!-- social -->
<div class="blog-social">
<!--
<a class="so-facebook" target="_blank" href="need to encode slug here"></a>
-->
</div>
<!-- ============== post ============== -->
{{{content}}}
<!-- ============ end post ============ -->
</div>
</div>
</div>
{{/with}}
- Template js -
Template.post.onCreated(function() {
var self = this;
self.autorun(function() {
var postSlug = FlowRouter.getParam('postSlug');
self.subscribe('singlePost', postSlug);
});
});
Template.post.helpers({
post: function() {
var postSlug = FlowRouter.getParam('postSlug');
var post = Posts.findOne({slug: postSlug}) || {};
return post;
}
// can't get these working in a helper, out of helper they crash the app
// console.log(this.slug);
// console.log(this.data.slug);
});
Template.post.onRendered( function () {
// these do not work
// console.log(this.slug);
// console.log(this.data.slug);
});
db.posts.findOne();
{
"_id" : ObjectId("576c95708056bea3bc25a91f"),
"title" : "How Meteor Raised the Bar For New Rapid-Development Technologies",
"post_date" : "May 28, 2016",
"image" : "meteor-raised-the-bar.png",
"slug" : "how-meteor-raised-the-bar",
"bitlink" : "ufw-29Z9h7s",
"tags" : [
"Tools",
"Technologies"
],
"excerpt" : "sizzling excerpt",
"content" : "bunch of post content html"
}
If some one can solve this using any method, I will accept answer with joy and gratitude most intense.
The problem is probably with the parent template, rather than this one. The way that Meteor works is that the JS files are separated from the HTML, so don't try to include a <script> tag in the HTML.
The first thing is that you have to load all of your documents into the client. (NOTE: once you've got the hang of that, then you can worry about only loading the documents that you need).
To do that, you need a collection and a publication. By default all collections are automatically published completely, so unless you removed the autopublished module, then I'll assume that it is still loaded.
So let's start with the parent template. In this case, I'm going to just loop through all of the posts in the collection and display them using the innerTemplate.
<template name=parent>
<ul>
{{#each post}}
{{> innerTemplate}}
{{/each}}
</ul>
</template>
And now our inner template might look like this:
<template name=innerTemplate>
<li>{{slug}}</li>
</template>
The end result will be a simple list with each slug.
Now, to link everything together, we need to create a JS file, which will:
1. define the collection on both client and server
2. pass the collection to the parent template
This file should be accessible to both the client and the server.
posts = new Mongo.Collection('posts');
if(Meteor.isClient) {
Template.parent.helpers({
posts() {
return Posts.find();
}
});
}
Now, if you want to do something with 'slug' in the JS file, you could do something like this:
if(Meteor.isClient) {
Template.innerTemplate.helpers({
upperCaseSlug() {
return this.slug.toUpperCase();
}
});
}
Then, you could refer to upperCaseSlug in your template, like thus:
<template name=innerTemplate>
<li>{{upperCaseSlug}}</li>
</template>
A few things about Meteor:
You should never see a pattern such as:
<script type="text/javascript">
...some code
</script>
Because Meteor combines all your js files into one big file and includes it automatically in your app. You should never have to declare your own script in this way.
Secondly, you should never have to get the value of a data object by reading the DOM. The data context of each template gives you your data in the variable this.
In either a helper or template event you can refer to this and be assured that you're going to get exactly the data being displayed in that instance of the template.
Having now seen your template code it's now apparent that your template has no data context - you set the data context inside your {{#with post}} and its associated helper but that doesn't end up creating the this you need one level below.
So... #Nathan was on the right track except that he assumed you were iterating over a cursor instead of just looking at a single post.
Take all html you have between your {{#with post}} and {{/with}} and put it in a new template, say postDetail then make your outer template:
<template name="post">
{{#with post}}
{{> postDetail}}
{{/with}}
</template>
Now your postDetail template will get a data context equal to the post object automatically and your helpers can refer to this safely.
Template.postDetail.helper({
slugURI{
return "/"+encodeURI(this.slug);
}
});
Then in your postDetail template you can get the encoded slug with:
<a class="so-facebook" target="_blank" href={{slugURI}}>

node.js ejs rerender div afte ajax

My issue is update div block after succes ajax call.
so I do it like that:
My div:
<div class="lists">
<% for(var i=0; i<searchItem.length; i++) {%>
<a class="list-link" href="#"><div class="list"><%= searchItem[i] %></div></a>
<% } %>
</div>
My jquery ajax call:
$.ajax({
url: '/search?val=' + encodeURIComponent($('#search-input').val()),
success: function(data) {
console.log('DATA-' + data);
new EJS({url:' /views/dropdown.ejs'}).update('lists',data)
}
});
My project structure:
But I got 404 error, because ejs cannot see dropdown.ejs template(http://localhost:3000/views/dropdown.ejs NOT FOUND). Why?
Another question what type of selector I need write in .update('lists',data) , Id or class of my div block?
I am assuming that you are using Express and views/dropdown.ejs is a view in your express backend.
If my assumption is correct, you can not directly access view of your backend. You have to create a router for this view or you can put this template in your static folder.
router.get('/template/:templateName', function(req, res){
res.render(req.params.templateName, { title: 'Template' });
});
// Or put your template inside public folder
app.use(express.static(path.join(__dirname, 'public')));
As for your second question regarding the selector for your DOM.It depends on what you want to achieve. Using class selector will get all the DOM with that class name and if give you an array of DOM, as for the ID (needs to be unique on a certain page) it will select the single DOM.
Looking at your sample, I think you need to use ID and target that DOM for updating the content.

Categories

Resources