Django: show something else before full request processing ends - html

I'd like implement a solution where a user can make a request to the backend and since the request takes some time to get the answer from the backed.
I want to render the same page with a loading animation without javascript. For this purpose, I set a variable "show_loading" on "true" to display the loading animation via the hmtl-file. The code is as follows:
views.py
def UploadView(request):
show_loading = True
context["show_loading"] = show_loading
render(request,'UPLOAD.html',context)
data = {}
#something else happening, just logical operations
return render(request,'UPLOAD.html',context)
UPLOAD.html:
{% if show_loading %}
<div class="loader">
<div class="inner one"></div>
<div class="inner two"></div>
<div class="inner three"></div>
</div>
{% endif %}
The problem is that the render function is not working by the first render line (without return) but with the second render line (with return). So the question is, does render always need return or what I am doing wrong here, that the render does not work without return?

You cannot use the backend to update the page with a classic Django view, since to communicate with the frontend you need to return a response (yes, render must return). The easiest way is to use Javascript: set a simple timer that updates the page if it does not receive a response after a certain time. If you really want to use the backend you need to create a channel between the backend and the frontend, take a look at this.

Related

Handlebars - Compile passed parameter (containing HTML) to template engine

I use expressjs and hbs(Handlebars) as the template engine.
One of the parameters that are passed to the template when loading the page contains HTML code.
When the page loads, instead of processing the parameter and displaying the elements, it is displayed as text.
How can I solve this?
//Server-side:
let parameter = "<h2 id="how-to-use">How To Use</h2>";
//HTML:
<div id="container">{{parameter}}</div>
//--------------------------------------
//result after page load
<h2 id="how-to-use">How To Use</h2>
//Instead of
How To Use
got it.
use the triple {{{ }}} brackets

Django Nested Views

I'm developing an internal application and I would like to be able to nest my views to keep everything nice and organized. I plan on doing this by keeping different parts of the page in their own HTML files with their own Views (separate sidebar and navbar, separate charts, etc).
views.py
from django.shortcuts import render
from django.views.generic import TemplateView
import Recall.data_logger.models as DLM
class ReportHome(TemplateView):
template_name = 'data_logger/index.html'
class SelectorSidebar(TemplateView):
template_name = 'data_logger/sidebar.html'
def get(self, request, *args, **kwargs):
companies = DLM.Company.objects.order_by('company_name').all()
return render(request, self.template_name, {'companies':companies,})
index.html
<html>
<head></head>
<body data-gr-c-s-loaded="true">
{% include 'data_logger/navbar.html' %}
<div class="container-fluid">
<div class="row">
{% include 'data_logger/sidebar.html' %} <!-- This is the part I need help with-->
</div>
</div>
</body>
</html>
sidebar.html
<div class="col-sm-3 col-md-1 sidebar">
<ul class="nav nav-sidebar">
{% for company in companies %}
<li>{{ company.company_name }}</li>
{% endfor %}
</ul>
</div>
I understand that by just using {% include 'data_logger/sidebar.html' %} it's just loading the HTML and bypassing SelectorSidebar, how do I direct it through the View?
I'd like a solution that allows me to access anything from a simple list of names to relitively large datasets being fed into a D3 chart.
Solution
This is what I ended up using:
index.html
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"
integrity="sha384-vk5WoKIaW/vJyUAd9n/wmopsmNhiy+L2Z+SBxGYnUkunIxVxAv/UtMOhba/xskxh"
crossorigin="anonymous"></script>
<script>
$.get("_sidebar", function(data, status){
$("#_sidebar").html(data);
});
</script>
</head>
<body data-gr-c-s-loaded="true">
{% include 'data_logger/navbar.html' %}
<div class="container-fluid">
<div class="row" id="_sidebar"></div>
</div>
</body>
</html>
Where _sidebar is the URL to SelectorSidebar:
urlpatterns = [
path('', v.ReportHome.as_view(), name='ReportHome'),
path('_sidebar', v.SelectorSidebar.as_view(), name='SelectorSidebar'),
]
I think you are making some confusion on how Django templates and views work together.
In very simple terms a Django template is what defines the HTML code that makes up a page. You can keep your templates very modular and organized; to do this you can use the include template tag or you can use template inheritance, which is a very powerful way to have "modular" templates.
A Django view is basically a function (or a class of you are using class based views) that receive an HTTP request and build an HTTP response.
It doesn't make much sense to have "nested" views because usually you have just one HTTP request and you want to build just a response with the HTML needed to display the page.
So I think that you can happily use Django templates to put together all the modules that make up your page (header, sidebar, etc.), but each page should correspond to a single Django view.
Another approach could use AJAX and Javascript to make different HTTP requests and build up the page client-side, but I think that this is not the approach you are considering here.
As #baxeico answered, you can't have multiple views to serve a page, because one HTTP request is one view.
If you have content that needs to appear on a lot of pages, like your sidebar, and that content also requires some context information to render (like a list of companies to fetch from the db), you have two options:
If the stuff required to add to the sidebar is fairly limited, create a template context processor that you add to the list of context processors in your settings (TEMPLATES setting).
def sidebar_context(request):
return {'companies': DLM.Company.objects.order_by('company_name').all()}
and in your settings, you'd add something like 'myapp.custom_contexts.sidebar_context' at the top of the list.
Now, every single template has access to the context variable companies, including your sidebar template.
If the stuff shown in the sidebar is more dynamic, or more complex, you should consider fetching the data from within the browser using AJAX. You would create a view that returns JSON instead of HTML and in your sidebar template add javascript to fetch the data and populate the sidebar.
The view is as simple as your current one:
def sidebar(request):
return JsonResponse({'companies': Company.objects.all().values('name', 'id')})
which will return a list of dicts containing name and id of each company. In your AJAX handler for the successful response (which receives the data), you can then loop through data and access data[i].name and data[i].id which you can use to populate your list.
I won't go as far as posting the full javascript (please search for jQuery, ajax and django) but here's a bit to give you an idea, assuming jQuery:
$(window).on('load', function() {
$.ajax({
url: "{% url 'sidebar' %}", // assuming this is inside a template, if not {% url %} won't work and you'll have to get it in a different way
success: function(data) {
if (data.length > 0) {
for (var i=0; i<data.length; i++) {
var elem = $("<li>" + data[i].name + "</li>")
$("#companies").append(elem)
}
}
})
})

Is it bad practice to create Divs just to have multiple controllers?

Is a bad practice to be creating divs in your HTML just to be able to have multiple controllers?
Since you cannot have them in one also the approach of having multiple directives with separate controllers seems like a hack, but correct me if I am wrong.
So I have 2 controllers - one is called ConvertController and the other one is called YouTubeLinkUIController.
The responsibility of the first one is to hit my Web API controller and convert the given YouTube link into an audio.
The responsibility of the second one is to control some of the UI functionality.
In order to follow the single responsibility principle, I have separated them into 2 different controllers and therein lies the problem.
My last commit, specifically Index.cshtml shows the full code, but for the sake of not making this messy I will abreviate it for this post.
https://github.com/AvetisG/TubeToTune/commit/e68ba42f20498c9a4e032328aed6d68c27b9b2cb
<div class="container" ng-app="TubeToTuneApp" ng-controller="YouTubeLinkUIController">
... more code
#*Scoping the Convert Controller*#
<div ng-controller="ConvertController">
... more code
</div>
</div>
Looking at your github commit message it looks like you split the controllers because you didn't want to have too much code in your ui controller.
This is a perfect example of when an angular service is in order. You can think of a service like a controller without all the overhead and that can be easily called from another controller
Angular Service Documentation
What you should do is define a service that calls your api and then
angular.module('youTube', [])
.controller('YouTubeLinkController', ['$scope', 'convert',
function($scope, convert) {
$scope.convertLink = function() {
$scope.convertMessage = convert.convertYoutube()
};
}
])
.factory('convert', [
function() {
var convertService = {};
convertService.convertYoutube = function(data) {
//Make api call
return "Conversion Done";
}
return convertService;
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="youTube">
<div ng-controller="YouTubeLinkController">
{{convertMessage}}
<button ng-click="convertLink()">Convert</button>
</div>
</body>
Naturally you should define the service in it's own page. That way controllers are only used for interacting with UI. It also solves your problem
It's absolutely fine to use divs\spans and nested structures and use ng-controller with it.
When you add ng-controller to a html element in a way you are creating a component with a model-view and controller.
A complex component can have nested sub components that perform very specific functionality and in a way you are demarcating such parts with ng-controller . To take it a step further if you convert these component into directives, with their own controller + template(view) and that accept model from a data source, then you have a reusable component that you can use throughout the app.
To me, it looks more like your ConvertController should be written as a service, rather than as a controller. This would still follow single responsibility, but would probably align closer to your intended functionality: UI functionality and view data in the controller, business logic in the service.
That said, having two controllers on a single view might not be bad practice, this leads to confusing mark-up in cases like the following:
<button type="submit" class="btn btn-xlarge btn-warning btn-block" ng-if="AreThereYouTubeLinks() == true" ng-click="ConvertToTunes(YouTubeLinks)">
You may know personally which controllers AreThereYouTubeLinks(), ConvertToTunes(), and YouTubeLinks belong to, but this will be confusing in the long-term (and can lead to issues with scope-bound variables like YouTubeLinks.
Luckily, there's a syntax for helping clear this up- Controller As - and Todd Motto wrote an excellent article explaining how to use it and what problems it helps solve. In brief, it would turn something like this:
<div ng-controller="MainCtrl">
{{ title }}
<div ng-controller="AnotherCtrl">
{{ title }}
<div ng-controller="YetAnotherCtrl">
{{ title }}
</div>
</div>
</div>
in to this:
<div ng-controller="MainCtrl as main">
{{ main.title }}
<div ng-controller="AnotherCtrl as another">
{{ another.title }}
<div ng-controller="YetAnotherCtrl as yet">
{{ yet.title }}
</div>
</div>
</div>
In your case, you would end up with this safer, more understandable mark-up:
<div class="container" ng-app="TubeToTuneApp" ng-controller="YouTubeLinkUIController as linkCtrl">
... more code
#*Scoping the Convert Controller*#
<div ng-controller="ConvertController as converter">
<button type="submit" class="btn btn-xlarge btn-warning btn-block" ng-if="linkCtrl.AreThereYouTubeLinks() == true" ng-click="converter.ConvertToTunes(linkCtrl.YouTubeLinks)">
</div>
</div>
If you're going to stick with two controllers, you probably want to consider investing the time to getting comfortable with Controller As.

Multiple API calls inside a Polymer Custom Element

I have put together a custom element using Polymer - <x-flickr> (http://tamas.io/x-flickr-custom-polymer-element/ || https://github.com/tamaspiros/x-flickr) - it essentially makes a REST call to the Flickr API and returns photos based on a search:
<polymer-jsonp id="ajax" auto url="http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key={{apikey}}&tags={{tag}}&per_page={{amount}}&page=1&format=json&jsoncallback="></polymer-jsonp>
This call returns some information about a particular photo but not everything. I'd like to reuse the unique ID returned via this call and make a second REST call to get further detail about the image. At the moment I display the photos via:
<template id="photos" repeat="{{photo in photos}}">
<div class="thumbnail">
<img src="http://farm{{photo.farm}}.staticflickr.com/{{photo.server}}/{{photo.id}}_{{photo.secret}}.jpg" class="img-thumbnail">
</div>
</template>
but I'd like to extend that so that I get the description of the photo as well (and this is the information that is not being returned by the first REST call displayed above) - so my template would look something like this:
<template id="photos" repeat="{{photo in photos}}">
<div class="thumbnail">
<img src="http://farm{{photo.farm}}.staticflickr.com/{{photo.server}}/{{photo.id}}_{{photo.secret}}.jpg" class="img-thumbnail">
<p>{{photo.description}}</p> <!-- this should come from the 2nd API call -->
</div>
</template>
What's the best way of achieving this?
I forked your project so you can see the details of what I'm about to describe here https://github.com/sjmiles/x-flickr.
The short answer to your question is to include a request element (polymer-ajax) inside the template repeat. That causes a request to spawn for each item in the repeat, and gives you easy access to the item data (the photo id in this case).
As I mentioned, you can see an example of how this can be done in the source here: https://github.com/sjmiles/x-flickr/blob/master/x-flickr.html#L46.
A few other notes:
You don't need JSONP for these requests, simple Ajax calls will do, you can access the JSON directly. I used polymer-ajax instead of polymer-jsonp.
You almost never need addEventListener in Polymer because you can listen to events using on-<eventName>="methodName" syntax directly in the HTML. In this case, you don't need to use events at all, because you can do the work with data binding.
This could be done completely script-free, but I kept your script for setting photos property and sending the x-flickr-load event.
HTH
One way to tackle this: http://jsbin.com/yihovepi/1/edit (also includes some refactoring)
The <p>{{photo.description}}</p> is always in the template, but the .description is filled later by dynamically creating <polymer-jsonp> for each photo.
Note, I'm also using binding to the main polymer-jsonp element's response property:
<polymer-jsonp id="ajax" response="{{response}}">
This is super changed because the corresponding responseChanged() callback is called when that value is populated from the request.

Razor: Retrieving variable from component template on page template

Hi all,
I've been working on a set of Razor templates that is either Site Editable with the Experience Manager and at the same time is fully responsive for several screenwidths with the Twitter bootstrap. As a result, I need to dynamically manipulate the DOM output based on what the Experience Manager editor adds or deletes but still maintain the responsive design. Part of this construction is adhering to the rules the twitter bootstrap dictates.
The twitter bootstrap allows for excellent responsive design by introducing dynamically calculated div widths using classes. A <div class="span12> uses the entire width of the wrapper, for example. A "span6" effectively uses half, with a certain margin calculated as well to allow for another div with "span6". However, this only works if the preceding class is called <div class="row-fluid">,and as long as the span<numbers> actually add up to exactly 12. The problem arises when I need to close the <div class="row-fluid"> when this number is actually reached.
To clarify: it has to output like this
<div class="row-fluid">
<div class="span6">..code</div>
<div class="span4">..code</div>
<div class="span2">..code</div>
</div>
The <div class="span[#]"> are rendered with a component template, in order to allow for multiple components within the <div class="row-fluid>, which the Page Template renders.
However, from a component template level I cannot seem to retrieve the actual amount of components of this template actually exist on the Page itself. I calculate the width of the component used based on a schema option of the component itself. I use the following Component Template code to render it correctly:
#{
var spanClass = String.Empty;
if (Fields.HasField("component_width") && Fields.component_width != null) {
if (Fields.component_width.ToLower() == "full") {
spanClass = "span12";
} else if (Fields.component_width.ToLower() == "half") {
spanClass = "span6";
} else if (Fields.component_width == "40%") {
spanClass = "span5";
} else if (Fields.component_width == "35%") {
spanClass = "span4";
} else if (Fields.component_width == "25%") {
spanClass = "span3";
}
}
}
<div class="#spanClass">...code
To get to my question: I need to be able to close the <row-fluid> div if the number 12 has been reached. So if one component with the options 'Full' (width) is selected, the following output code needs to appear:
<div class="row-fluid">
<div class="span12">..code</div>
</div>
If there are two components on the page with the option "half" are selected, it must allow
<div class="row-fluid">
<div class="span6">..code</div>
<div class="span6">..code</div>
</div>
mind the closing div on the end. Is there some way I can reach the variable i created on the Component Template var spanClass = String.Empty; from Page Template? Something like:
#foreach (var cp in GetComponentPresentationsByTemplate("XM_Generic Content")) {
#if (cp.Component.spanClass == "span6") {
<div class="row-fluid">
#cp.RenderComponentPresentation()
#if (cp.Index == 1) {
</div>
}
}
}
I'm still getting to know Razor templates, the practicalities of Responsive design and ofcourse StackOverflow. Chances are that I completely missed something, made dumb errors in my code of just asked a silly question. By all means, let me know.
The package is not shared between template runtimes, so this behavior is normal (not being able to see variables set in one template from a different instance).
There are ways around this, but you should consider that perhaps there is a good reason why Tridion chose to isolate the template execution.
See here for one of the ways to go around this.
Standard techniques using the ContextVariables dictionary don't allow you to set something in the CT and access it from the PT. Effectively, each time a Component is rendered, the render context gets a fresh copy of the variables from the page render context. Writing back to them, therefore isn't effective. There is a technique that gets round this, which is described in detail on tridion-practice. As already noted, resorting to these kinds of techniques shouldn't be your first option, but sometimes you need to.
Currently, its seems, the user is defining the width position in the component field. I think, its quite typical, but if you create 5 Component Template which will call a same Razor TBB, and also define, a parameter schema on component Template where can set the width of component then afterwards you can easily call these different CTs in the page template.