Python Flask Web App Navigation Without Page Refresh - javascript

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.

Related

How to use client side javascript variables as array index?

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

Laravel 5.1 - Javascript not loaded

My app gets the views from an ajax request by navigation.
So when i click a link in my menu i retrieve all the Html that my view contains.
My javascript is included inside the main template and of course all my calls works.
But once i need for example to create an animated filter gallery inside a specific view, the javascript for that view doesn't work.
This is how i've organized my app:
My template
<!-- !Doctype -->
#include('partials.doctype')
<!-- Menu -->
#include('partials.menu')
<!-- Cont -->
<section id="content-wrapper">
#include('ajax.index')
</section>
<!-- Footer -->
#include('partials.footer')
<!-- Javascript -->
#include('partials.javascript')
</body>
</html>
My Controller (if there's an ajax call i retrieve the view without #extends() and #section(), otherwise i retrieve my full view):
// load page
public function loadPage($page){
return (\Request::ajax()) ? view('ajax.'.$page)->render() : view('pages.'.$page);
}
My views:
For my purpose i've created 2 type of views, one extended and one with only the html i need from my ajax calls.
a) extended, it's inside "pages" folder:
#extends('main')
#section('cont')
#include('ajax.shop')
#stop
b) only html, for ajax calls, inside "ajax" folder:
<div class="content">
<div class="container-fluid">
<div class="row page-title-box">
<h3 class="page-number">N. 67</h3>
<h1 class="page-title">Shop</h1>
</div>
</div>
</div>
I don't understand where to put my javascript for this view if i need to implement an animated filter gallery. I've tried to put javascript inside the view but my app crashed.
Your javascript should be in your public folder in a folder like public/js.
Then in your partials.javascript include your js:
<script src="/js/main.js"></script>

Iron Router: Load js script after template has been rendered

I'm trying to load a javascript file (using IRLibloader) after the Iron Router has rendered the template:
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
});
Router.route('/', {
name: 'landing',
template: 'landing',
onBeforeAction: function () {
var googleAPI = IRLibLoader.load('http://maps.googleapis.com/maps/api/js?libraries=places&sensor=false');
var fancyInput = IRLibLoader.load('/js/fancyInput.js');
var geoComplete;
if(googleAPI.ready()){
geoComplete = IRLibLoader.load('/js/jquery.geocomplete.min.js');
}
if(googleAPI.ready() &&
fancyInput.ready() &&
geoComplete.ready()){
console.log('All ready');
this.next(); // Render the page when all the libraries are ready
// Testing this here
if(Meteor.isClient){
console.log("Meteor.isClient");
IRLibLoader.load('/js/landing.js');
// Set places autocomplete
Template.landing.rendered = function(){
$('section :input').val('').fancyInput()[0].focus();
$('section :input').geocomplete();
console.log("loading.js ejecutandose (after render)");
}
}
}
}
});
But when I browse localhost:3000, the layout gets rendered, the googleAPI, fancyInput and geocomplete libraries are loaded too since the 'all ready' message gets printed at console, and landing.js also gets loaded (since it loads the background image and the message 'Meteor.isClient' also gets printed).
But then, the 'landing' template never gets rendered. Its content does not appear, and the console message inside the Template.landing.rendered never gets printed. This is the template.js file:
<template name="landing">
<img id='logo' src="img/logos/logo.png">
<div id='content'>
<section class='input'>
<div>
<input type='text' placeholder='Type text here'>
</div>
</section>
</div>
</template>
I also tried loading landing.js with onAfterAction, which seems to happen before the onBeforeAction according to the Firebug console. How strange!
I can't understand why the template is not being loaded, since no error appears at meteor console. Any idea?
EDIT: it does work if I remove the layout, which looks like this:
<template name="layout">
<head>
<title>Welcome to my app</title>
</head>
</template>
What's wrong with this layout?
So, I think you might be overthinking this a little. Why not use existing packages for these libraries? Aside from being significantly easier to use, some of that 3rd party code would get minified into the main app js file instead of making additional HTTP requests to download them.
For example, dburles:google-maps gets you the Google Maps API and extra libs of your choice (with the option to only load on specific routes) and jeremy:geocomplete gets you Geocomplete (which automatically installs that maps package as a dependency). See the jeremy:geocomplete README for implementation.
As for Fancy Input, why not create a simple Meteor package wrapper for that so you can just meteor add fancy-input?
Also, your Template.landing.rendered callback should not be in an onBeforeAction. Ideally, it should be in its own file with other code for the landing template.

Multiple layouts with Angular

I am building an Angular app and hitting a bit of a snag in how to handle the home page. The home page is 90% different - only the header stays the same - in there I have directives that show user login state for ex.
To make use of routing/templates etc I'd ideally like to have my ngview in the white area of sample shown - that all works fine - just not sure how to build the home page. It doesn't need an ngview area persay since it's the only one of it's kind. I don't want to make it as a second apps however as that seems wasteful and would reload everything.
Googling this brings up suggestions of replacing the white area with a directive but then I think I would lose the whole routing/template benefit.
Alternatives I have seen have code to determine if on home and load a body CSS class etc but that is not ideal either as the content is so different.
UI Router is a possibility but I'd like to avoid prebeta stuff if possible.
Suggestions?
You could have this:
index.html:
<body>
...header..
<div ng-if="isHomePage()">
<div ui-view></div>
</div>
<div ng-if="!isHomePage()">
<div ng-include="'shell.html'"></div>
</div>
...footer..
</body>
home.html (with route '/')
...your home page html...
shell.html (any route different than '/')
<div>
<div>
<div ui-view></div>
</div>
<aside><aside>
</div>
finally, add isHomePage() to your root scope
$rootScope.isHomePage = function() {
return $location.path() == '/';
};

AngularJS dynamically set param of ngInclude based on route

I'm trying to dynamically include a template into my index.html. The general structure of index.html is:
<body>
<header ng-controller="Main">
<section>
<!-- global stuff -->
</section>
<section ng-include="moduleName + '/views/menubar.html'">
<!-- module-based stuff -->
</section>
</header>
<div id="view" ng-view></div>
</body>
Sample URL
example.com/<app_name>/index.html#/<module_name>[/method_name]
I can't figure out how to update $scope.moduleName when the route changes. My trouble is two-fold:
The header's controller is Main, not the controller associated with the view, so I can't? update $scope.moduleName from the view's controller (because Main and the view's controller are siblings).
In Main, I tried setting a $scope.$on('$routeChangeSuccess',…), but apparently it is not notified of route changes.
I've thought of setting up a $rootScope.$on listener (as described in SO#15355346) for the route change and broadcasting down to children, who then emit back up their route, which is broadcasted back down so it is available to Main. But that seems heinous.
And I would really prefer to keep the header outside of ng-view.
EDIT I noticed that $route.current.scope has an object named with module_name (possibly because the name of the controller associated with the route's module_name is the same). I'm wondering if I might be able to somehow use the name of that object…
It's hard to say what's wrong in your code without the full picture. Things you show look fine to me.
Please see this plunk I've created to display the ability to do it. Take note that you also can extend route objects with custom properties, like moduleName here:
$routeProvider.when('/page1', {
template: 'one',
controller: 'one',
moduleName: 'firstModule'
});

Categories

Resources