how to load an alert inside an if statement twig - ajax

i want to load an alert from js script that should only run if the condition is met:
Code:
{% if user_perm.up_slug != "view_hospitals" %}
<!-- <frame id="info" onload="errorLoad()"></frame> -->
<!-- <div id="info" onload="errorLoad()"></div> -->
<script type="text/javascript">
errorLoad();
function errorLoad()
{
$.confirm({
icon: 'fa fa-question-circle-o',
theme: 'supervan',
closeIcon: true,
animation: 'scale',
type: 'orange',
title: 'Sorry',
content: "Your not permitted to view this page",
buttons: {
"Go Home": function () {
window.location.replace('{{ base_url() }}/dashboard');
}
}
});
}
</script>
{% else %} ... {% endif %}
i know onload doesnt work on div, but what i want is if the condition is met on the if statement, then the script pops up an alert.
what i want is i want the function errorLoad() to run when the if condition is met

Related

Flask, WTForms - send the whole form using ajax

I am wondering how to send the whole wtform using ajax request (this one does not work):
function addReport(e){
e.preventDefault();
var serializeData = $('form').serialize();
$.ajax({
type:'GET',
url:'/reports_list',
data: serializeData,
success:function(result){
},
async: false
});
}
I have one main form, which includes another:
Reports = FieldList(FormField(ReportsForm))
The idea is to render the form under form, in case user wants to add another one. In short, it should just copy this underform and clone it, then renders to the main one.
How can I pass the entire form in ajax request?
It seems to me that you are trying to nest form elements. So you only send the innermost form. The validation errors are also not displayed when the form is sent via AJAX.
I think you can follow your approach more easily if you add the necessary form fields by cloning with JavaScript without submit.
The following example breaks the nested forms into fieldsets.
If a fieldset is to be added, the previous one is cloned and the necessary attributes are adapted to the requirements.
When removing, the last one is removed.
from flask import (
Flask,
render_template,
request
)
from flask_wtf import FlaskForm
from wtforms import FieldList, FormField, StringField, SelectField
from wtforms.validators import DataRequired
app = Flask(__name__)
app.secret_key = 'your secret here'
class ReportForm(FlaskForm):
class Meta:
csrf = False
title = StringField('Name', [DataRequired()])
lang = SelectField('Language', choices=[('cpp', 'C++'), ('py', 'Python'), ('text', 'Plain Text')])
class ReportsForm(FlaskForm):
reports = FieldList(FormField(ReportForm), min_entries=1)
#app.route('/reports', methods=['GET', 'POST'])
def reports():
form = ReportsForm(request.form)
if form.validate_on_submit():
for report in form.reports.data:
print(report)
return render_template('reports.html', **locals())
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Reports</title>
</head>
<body>
<form name="my-form" method="post">
{{ form.csrf_token }}
{% for subform in form.reports -%}
<fieldset name="subform">
{% for field in subform -%}
<div>
{{ field.label() }}
{{ field() }}
{% if field.errors -%}
<ul class="errors">
{% for error in field.errors -%}
<li>{{ error }}</li>
{% endfor -%}
</ul>
{% endif -%}
</div>
{% endfor -%}
</fieldset>
{% endfor -%}
<button id="btn-less" type="button">Less</button>
<button id="btn-more" type="button">More</button>
<button type="submit">Submit</button>
</form>
<script type="text/javascript">
(function() {
const btnMore = document.querySelector('#btn-more');
btnMore.addEventListener('click', function() {
// Clone the previous fieldset element.
const subform = document.querySelector('fieldset[name="subform"]:last-of-type');
const newform = subform.cloneNode(true);
// Remove possible validation error messages.
const errors = newform.querySelector('.errors');
errors && errors.remove();
// Update the necessary attributes.
const fields = newform.querySelectorAll('input, select');
fields.forEach(field => {
const attrName = field.name;
field.name = field.id = attrName.replace(/^(.*)-([0-9]+)-(\w+)$/g, (...args) => {
return [args[1], Number(args[2]) + 1, args[3]].join('-');
});
field.value = '';
const labels = newForm.querySelectorAll(`label[for="${attrName}"]`);
labels.forEach(label => label.setAttribute('for', field.id));
});
// Add the new fieldset.
subform.after(newform);
});
const btnLess = document.querySelector('#btn-less');
btnLess.addEventListener('click', function() {
const subforms = document.querySelectorAll('fieldset[name="subform"]');
if (subforms.length > 1) {
// Remove the last of the fieldset elements.
subforms[subforms.length - 1].remove();
}
});
})();
</script>
</body>
</html>

Explanation about data-apos-ajax-append outside pieces-pages

I want to implement the apostrophes Ajax features in my project but sadly I don't understand the Ajax functions not completely. I have been studying the documentation for the last week now but i don't find enough information about that topic. I want kindly ask if it's possible to use data-apos-ajax-append outside of apostrophe-pieces-pages
I created a widget like that:
lib/modules/infinite-widgets/index.js
module.exports = {
extend: 'apostrophe-widgets',
label: 'Infinite Widget',
addFields: [
{
name: 'posts',
label: 'Posts',
type: 'array',
titleField: 'name',
schema: [
{
name: 'name',
type: 'string',
label: 'Name'
},
{
name: '_image',
type: 'joinByOne',
withType: 'apostrophe-image',
label: 'Image',
required: true,
filters: {
projection: {
attachment: 1,
description: 1,
title: 1
}
}
}
]
}
]
};
lib/modules/infinite-widgets/views/widget.html
<div class="row margin">
<div class="col s12 m12">
<div class="radius
{% if data.widget.shadowOn == true %}
z-depth-1
{% endif %}
">
<div data-apos-ajax-context="infinite">
{% include "indexAjax.html" %}
</div>
</div>
</div>
</div>
lib/modules/infinite-widgets/views/indexAjax.html
<div data-apos-ajax-append>
{% for name in data.widget.posts %}
{% set image = apos.images.first(name._image) %}
<div class="card z-depth-0" style="
{%- if piece.backColor-%}
background-color:{{ piece.backColor }}
{% endif %}
">
<div class="card-image">
<img src="{{ apos.attachments.url(image, { size: 'one-sixth' }) }}" />
</div>
<div class="card-content">
{{ name.name }}
</div>
</div>
{% endfor %}
</div>
That is working pretty nice but unfortuantly It displays all posts created simultansiosly and I wasen't able to use the "Load More..." button with AJAX here
{# Load More button. Also outside data-apos-ajax-append, so it gets refreshed #}
{% if data.currentPage < data.totalPages %}
{# "Load More" button with the "append=1" flag #}
Load More...
{% endif %}
So can I modify this query, to have a load more button, or even better data-apos-ajax-infinite-scroll for content of an array created in an widget instead of an piece?
No, it is not possible to do that using data-apos-ajax-append. That feature is specifically for apostrophe-pieces-pages and there is no back end implementation waiting to talk to it for widgets, for instance.
You should instead look at writing a browser-side widget player for your widget, which gives you a place to make your own API calls back to the server. You can see that technique in the source of the apostrophe-twitter-widgets module.

waypoints infinity scroll loads all pages at once

I'm using Waypoint infinity scroll in my Django template.
<div class="infinite-container">
{% for item in arbitrase_records %}
<div class="col-lg-3 arbitrase-item">
<!-- item content -->
</div>
{% endfor %}
</div>
{% if page_obj.has_next %}
<a class="infinite-more-link" href="?page={{ page_obj.next_page_number }}">More</a>
{% endif %}
and the javascript goes like
<script src="{% static 'theme/js/waypoints/lib/jquery.waypoints.min.js' %}"></script>
<script src="{% static 'theme/js/waypoints/lib/shortcuts/infinite.min.js' %}"></script>
<script>
var infinite = new Waypoint.Infinite({
element: $('.infinite-container')[0],
items: '.col-lg-3.arbitrase-item',
onBeforePageLoad: function () {
$('.infinite-loading').show();
},
onAfterPageLoad: function ($items) {
$('.infinite-loading').hide();
},
offset: -30
});
</script>
for the first time, I scroll the page a little down, it loads all pages at once.
I have been trying different parameters to use with offset. setting offset to less than 30 like -20 or -10 stops the plugin to load any page.
How can I make it load only next page and wait for further scroll?
I also tried setting 'bottom-in-view' in offset (although, it is default). But then it loads all pages even without scrolling the page.

Django, submiting a form via AJAX

I have seen answers (here and here) for similar questions, but none of them work in my case. I have a simple form in a template, I am using bootstrap for rendering.
Once I submit the form, the response is rendered directly in the browser. When I return to the previous page (with the browser's button) then the success part of the AJAX call is executed.
forms.py
class QueryForm(forms.Form):
query = forms.CharField(label='Discover something', max_length=256)
views.py
def query_view(request, id):
if request.method == 'POST':
# Just for testing, send True
response_data = {
'result': True
}
return HttpResponse(json.dumps(response_data), content_type="application/json")
else:
try:
# Create a form and send it to the template
query_form = QueryForm()
return render(request, 'query_template.html', {'query_form': query_form})
except ObjectDoesNotExist:
return render(request, 'error.html')
urls.py
urlpatterns = [
url(r'^query', views.query_view, name='query_view'),
url(r'^', views.home, name='home'),
]
query_template.html
{% extends 'base.html' %}
{% load static %}
{% load bootstrap3 %}
{% block content %}
{# Display a form #}
<form method="post" class="form">
{% csrf_token %}
{% bootstrap_form query_form %}
{% buttons %}
<button class="btn btn-primary" id="query-button">
{% bootstrap_icon "star" %} Submit
</button>
{% endbuttons %}
</form>
<ul id="result"></ul>
<script src="{% static 'scripts/main.js' %}"></script>
{% endblock %}
main.js
$('#query-button').click(function (event) {
$.ajax({
url: "/query/",
type: "POST",
data: {},
cache: false,
// handle a successful response
success: function (json) {
console.log(json); // log the returned json to the console
$("#result").html("<li>" + json.result + "</li>");
console.log("success"); // another sanity check
},
// handle a non-successful response
error: function (xhr, errmsg, err) {
console.log(xhr.status + ": " + xhr.responseText);
}
});
});
// It also includes functions to manage the CRFS token
I have been playing with the code. If instead a form I use <input> and <button id='query-button'> it renders the response without reloading the page.
You need to prevent the default submit action of the HTML form, via event.preventDefault().
You can using FormData instead of custom send data, open below links:
How to send FormData objects with Ajax-requests in jQuery?
https://developer.mozilla.org/en-US/docs/Web/API/FormData

Render template into Symfony2 with ajax

I have a action in my controller for the index route
routing.yml
index:
pattern: /index
defaults: { _controller:AcmeDemoBundle:Default:index }
Controller for this path
public function indexAction()
{
return $this->render('AcmeDemoBundle:Plugin:index.html.twig');
}
And the index.html.twig template
{% extends'::base.html.twig' %}
{% block stylesheets %}
{% stylesheets filter='cssrewrite' output='css/*.css'
'bundles/acmedemo/css/*' %}
<link href="{{ asset_url }}" type="text/css" rel="stylesheet" />
{% endstylesheets %}
{% endblock stylesheets %}
{% block body %}
<br>
<div class="container">
<div class="wp_attachment_holder">
<div class="imgedit-response" id="imgedit-response-8"></div>
<div class="wp_attachment_image" id="media-head-8">
<p id="thumbnail-head-8"><img class="thumbnail" src="http://localhost/wordpress/wp-content/uploads/2014/06/121-1024x583.jpeg" style="max-width:100%" alt=""></p>
<p><a class="btn btn-sm btn-default" id="edik-wp-extended-edit">Редактировать</a> <span class="spinner"></span></p>
</div>
<div style="display:none" class="image-editor" id="image-editor-8">
</div>
</div>
<div id="output"></div>
<img class="thumbnail" data-attach-id="8" data-src="http://localhost/wordpress/wp-content/uploads/2014/06/121-1024x583.jpeg" style="max-width:100%" alt="">
<script>
$('#edik-wp-extended-edit').click(function() {
window.location= Routing.generate('ajax');
// $('#output').load('/ajax/index');
});
</script>
</div>
{% endblock %}`
When the button Редактировать is clicked i want to load another template with ajax.
another.html.twig
<div>Hello</div>
routing.yml
ajax:
pattern: /ajax/index
defaults: { _controller :AcmeDemoBundle:Default:ajax }
options:
expose: true
Controller for this path
public function ajaxAction()
{
$template = $this->renderView('AcmeDemoBundle:Plugin:another.html.twig');
return new Response($template);
}
But when i click the button my uri will be /ajax/index. What i want is that it stays by /index and the template will be rendered into my index template
What am i doing wrong?
Thanks.
First, your ajaxAction() should be a bit different as far as I know.
For me this works:
$template = $this->forward('AcmeDemoBundle:Plugin:another.html.twig')->getContent();
$json = json_encode($template);
$response = new Response($json, 200);
$response->headers->set('Content-Type', 'application/json');
return $response;
The forward() function renders the template and returns the rendered HTML code.
Your JavaScript file should look like this:
$.ajax({
type: "POST",
dataType: 'json',
url: Routing.generate('ajax'),
async: false //you won't need that if nothing in your following code is dependend of the result
})
.done(function(response){
template = response;
$('#your_div').html(template.html); //Change the html of the div with the id = "your_div"
})
.fail(function(jqXHR, textStatus, errorThrown){
alert('Error : ' + errorThrown);
});
You make an AJAX call to the your ajaxAction, which will return the HTML of the template you want to be rendered.
After that you just need to add a <div id="your_div"></div> at the position you want the template to be rendered. This workes perfectly for me.
To mention is that you need to break down the ajax template to just the code that should be shown.
Please try generate ajax route like this
window.location= '{{ path("ajax") }}';
Added:
For make ajax request change windows.location to ajax request
$( "#output" ).load( '{{ path("ajax") }}', function() {
alert('Load done');
});
Added explanation of use:
js code will work only if you put it on Twig template. If you put it to js file it will not work.
In case of original questions.
<div id="output"></div>
<img class="thumbnail" data-attach-id="8" data-src="http://localhost/wordpress/wp-content/uploads/2014/06/121-1024x583.jpeg" style="max-width:100%" alt="">
<script>
$('#edik-wp-extended-edit').click(function() {
$( "#output" ).load('{{ path("ajax") }}');
});
</script>
You can use something like FOSJsRoutingBundle to proper use SF2 routing in js

Resources