Hi I am trying to create a printable page from data send by a form in octobercms
I have created a plugin component which I have called PrintPageForm
<?php namespace Acme\PrintPage\Components;
use Cms\Classes\ComponentBase;
use Input;
class PrintPageForm extends ComponentBase
{
public function componentDetails()
{
// TODO: Implement componentDetails() method.
return
[
'name' => 'Print Page Form',
'description' => 'Detail page print form'
];
}
public function onHandleForm()
{
$var =
[
'overview' => Input::get('print_overview'),
'photos' => Input::get('print_photos')
];
I have this in the default htm file
<form action="/print" data-request-data="printpageform::onHandleForm" data-request-validate data-request-flash accept-charset="utf-8" class="form ajax-form">
<h3 class="sub-heading">Print Details</h3>
<p>To build a printer friendly formatted page, please select from the options shown below:</p>
<ul class="print-section">
<li>
<input type="checkbox" class="checkbox-input" value="1" name="print_overview" id="print_overview">
<label class="checkbox-label period" for="print_overview">Overview: Summary and key features alongside a photo of the property.</label>
</li>
<li>
<input type="checkbox" class="checkbox-input" value="1" name="print_photos" id="print_photos">
<label class="checkbox-label period" for="print_photos">Photos: Photo gallery of the property.</label>
</li>
</ul>
<input type="hidden" name="print" value="1">
<button class="btn button-large one-third palm-one-whole" type="submit" rel="print" >Print</button>
</form>
I am trying to access the value of print_overview and print_photo values in my print view page but can not figure out how to access these values I can see these values being passed in Debugbar as follows "request_query
array:2 [ "print_overview" => "1" "print" => "1" ]" and in my view file I have
{%if "print_overview" == "1" %}
{{ 'checked' }}
{% else %}
{{ 'Not Checked' }}
{% endif %}
but it does seem to matter what the value of print_overview is the page only echos out Not Checked I'm in a rut that I can't figure out any thoughts would be gratefully accepted.
Couple of pointers. When rendering a form in Twig, you should use either the {{ form_open() }} or {{ form_ajax() }} tags
Secondly, you can access the request data via the post() function in your component class; and you pass it to your view (the component partial) through the page property. So, your handler would like something like:
public function onHandleForm()
{
// Pass the variables to the view renderer
$this->page['print_overview'] = (bool) post('print_overview');
$this->page['print'] = (bool) post('print');
// Return a partial response http://octobercms.com/docs/ajax/update-partials#pushing-updates
return ['#view-response-element' => $this->makePartial('#response')];
}
While your response.htm partial file would look something like this:
{% if print_overview %}
"checked"
{% else %}
"not checked"
{% endif %}
As a note, if you are using the {% macro %} tags, these do not have access to the local scope of the partial file, i.e. they do not have access to the variables provided to the view. Any evaluation done within {% macro %} tags needs to be based on variables passed to it.
The best strategy for printing I find is to use JavaScript:
<!-- Link to print -->
<p>Print this invoice</p>
<!-- Invoice printer -->
<script type="text/template" id="invoiceTemplateContents">
Printable contents go in here
</script>
<!-- Script -->
<script>
function printInvoice() {
var printWindow = window.open('','','left=0,top=0,width=950,height=500,toolbar=0,scrollbars=0,status=0')
printWindow.document.write($('#invoiceTemplateContents').html())
printWindow.document.close()
printWindow.focus()
printWindow.print()
printWindow.close()
}
</script>
Related
I will have a strange question.
Version: Django version 3.0.8
This is my Javascript code:
fetch(`/loadbox/${message.id}`)
.then(response => response.json())
.then(dialog => {
let detailcontent=
`<div class="hepsi">
<div class="sender">
<h3>${dialog.sendername}</h3><br>
#${dialog.sender}</div>
<p class="posting msj"> ${dialog.content}</p>
<p class="posting rep"> ${dialog.reply}</p> // Here I have a list named replies and I want
to loop through all elements and display every reply for that particular message.
<br>
<div class="m-form">
<form class="form-control">
<input class="msj-i" type="text" placeholder="Start a new message"></input>
<input type="submit" value="Send" class="msj-s"></input>
</form> </div></div>` ;
document.querySelector('#message-view').innerHTML=detailcontent;
document.querySelector('.msj-s').onclick = function() {
sender=`${dialog.sender}`
reply_message(sender);
}
})
}
so where I fetch the data /loadbox/message.id, I have this data for example:
{"replies": ["hi there", "haha", "last"],"sendername": "Bilge", "sender": "bilge", "content": "hi"}
As you see replies is a list and I want it to loop through in the HTML template. However, I use dynamic content in my javascript code. Normally in Django template, I would easily do
{% for reply in replies %}
{{reply }}
{ % endfor %}
However, I am writing a dynamic html with this method:
content = `"some content"`
document.querySelector(".message-view").innerHtml = content
So I need to loop this through inside of the content I think. I tried:
{for (${reply} of ${replies})}
<p class="posting rep"> ${reply} </p>
it gave this error.
Uncaught (in promise) ReferenceError: reply is not defined
Or I tried :
{% for ${reply} in ${replies} %}
{{reply}}
{% endfor %}
but it gives the error:
Couldn't parse the remainder of ${replies}
So I am not sure if this is even possible, If you have any suggestions for changing my logic or etc I would be appreciated.
For demonstration; If click on a message on the left, it opens up the message on the right, you can reply to it, And I want it to display all of the replies there. Currently, it is undefined because I put whole list not the elements.
Inside template literals you can use the Array.prototype.map() method to loop over the replies and return a string for each reply. Now you'll have an array with strings in them. Last step is to turn the array into a combined string with the Array.prototype.join() method. Use an empty string as separator to join the strings together.
fetch(`/loadbox/${message.id}`)
.then(response => response.json())
.then(dialog => {
let detailcontent = `
<div class="hepsi">
<div class="sender">
<h3>${dialog.sendername}</h3>
<br>
#${dialog.sender}
</div>
<p class="posting msj">${dialog.content}</p>
${dialog.replies.map(reply =>
`<p class="posting rep">${reply}</p>`
).join('')}
<br>
<div class="m-form">
<form class="form-control">
<input class="msj-i" type="text" placeholder="Start a new message">
<input type="submit" value="Send" class="msj-s">
</form>
</div>
</div>
`;
document.querySelector('#message-view').innerHTML = detailcontent;
document.querySelector('.msj-s').onclick = function() {
sender = `${dialog.sender}`
reply_message(sender);
}
});
The issue I'm having is that various translations on the page use URL parameters to fill in the content for a form dynamically. The form has radio buttons and I want to have one of them checked by default depending on the URL Parameter.
So for example, if the URL says ?lang=dk, I would want the European radio button to be checked, but if it says ?lang=fr-ca, I'd want it to check North America:
<form id="contact-form" method="post" class="form-contact" enctype="multipart/form-data">
<div id="form-platform" class="form-platform--radio-group">
<label class="radio--button" for="option-na">
<input class="form__input" type="radio" id="option-na" name="platform"
value="NA">
<i></i>
<span class="radio--label">North America</span>
</label>
<label class="radio--button" for="option-eu">
<input class="form__input" type="radio" id="option-eu" name="platform"
value="EU">
<i></i>
<span class="radio--label">Europe</span>
</label>
</div>
</form>
So far, I've tried using this.param but it's been unsuccessful so far.
Is my only option to use Javascript to achieve what I need, or is this possible with OctoberCMS?
For Clarification:
A url like "example.com?lang=us" is making a request on the server. The request is Input::get('lang') = 'us'.
A url like "example.com/:lang?/" is using the Laravel routing system to access parameters of the slug. This would look like "example.com/us/page" and the request looks like this.param('lang') = 'us'.
Both of these could work for your system depending on how you are setting the language.
My recommendation is to design your website with dynamic values in mind and use collections like this.
PHP CODE in CMS page for adhoc:
function onStart() {
$language = Input::get('lang'); //check for a language request
$languages = [ //build language array
'dk' => [
'place' => 'European',
'selected' => false,
'value' => 'eu'
],
'fr-ca' => [
'place' => 'North America',
'selected' => false,
'value' => 'na'
]
];
if (isset($languages[$language])) {
$languages[$language]['selected'] = true; //see if the language request is in the array then set selected to true
}
$this['languages'] = $languages; //return languages to the page
}
In your Markup side of the page you can then do this - With twig you can just make a for loop set the variables and check to see if the language is selected.
<form id="contact-form" method="post" class="form-contact" enctype="multipart/form-data">
<div id="form-platform" class="form-platform--radio-group">
{% for language in languages %}
<label class="radio--button" for="option-{{ language.value}}">
<input class="form__input" type="radio" id="option-{{ language.value }}" name="platform"
value="{{ language.value | upper }}" {% if language.selected %}checked{% endif %} >
<i></i>
<span class="radio--label">{{ language.place }}</span>
</label>
{% endfor %}
</div>
</form>
So I am new to Django and a complete novice at JavaScript. I am trying to create a view which renders multiple forms dynamically using JavaScript. Below are two forms that I have created.
class CreateTestForm(forms.ModelForm):
class Meta:
model = Test
fields = ['name', 'test_group', 'description', 'query_text', 'failure_condition', 'status']
def getKey(self):
return "create_test_form"
class VC1Form(CreateTestForm):
expected_relation = forms.ChoiceField(choices = [('<','<'), ('>','>'), ('=','='), ('<=','<='), ('>=','>='), ('!=','!=')], required = True, label = 'Expected Relation: ')
num_rows = forms.IntegerField()
def getKey(self):
return "vc1_form"
In addition, I have the following view
def create_test(request):
context = {
'all_validation_classes': ValidationClass.objects.all()
}
for form in [CreateTestForm, VC1Form]:
if request.method == 'POST':
f=form(request.POST)
if (f.is_valid()):
return HttpResponseRedirect('/test_created/')
else:
return HttpResponseRedirect('/test_not_created/')
else:
f = form()
context[f.getKey()] = f
return render(request, 'create_test.html', context)
And template:
<form action="/tests/create/" method="post">
{% csrf_token %}
{{create_test_form.as_ul}} <br><br>
<select id="validation_classes_id" name="all_validation_classes" onchange="showForm()">
<option value="%">Choose the validation class</option>
{% for val_class in all_validation_classes %}
<option value="{{ val_class.id }}">{{ val_class.id}} {{val_class.name }}</option>
{% endfor %}
</select>
<br><br>
<script>
function showForm(){
var x = document.getElementById("validation_class_id").value;
}
</script>
<input type="submit" value="Submit" />
I am trying to get to a point, where, when the user selects something from the dropdown (validation_classes_id), the view will render the form corresponding to that selection. I have currently included only one additional form VC1Form here but I have written different forms corresponding to each option in the drop down.
I have tried a few things but nothing has worked yet and any help would be appreciated!
Try something this:
document.getElementById('form').querySelectorAll("label").forEach( e =>
{e.prepend(document.createElement("br"));});
Even better would be:
<form id="form" action="login_view" method="post">
{% csrf_token %}
<table>
{{ form }}
</table>
<input type="submit" value="register">
I'm trying to port an application with an existing db. I'm using db_column to have django model Foreign Keys correctly while using the existing database names and columns.
models.py
class foo(models.Model):
foo_id = models.AutoField(primary_key=True, blank=False, null=False)
foo_name = models.CharField(max_length=500, blank=True, null=True)
foo_type_lookup = models.ForeignKey('foo_type_lookup', to_field="foo_type_id", db_column="foo_type", blank=True, null=True)
class foo_type_lookup(models.Model):
foo_type_id = models.AutoField(primary_key=True, blank=False, null=False)
foo_type = models.CharField(max_length=500, blank=False, null=False)
The table foo_type_lookup has two rows (ids 0 and 1) for foo_type 'bar' and 'baz'. I'm trying to make a form to add a record in the foo table which will have a foreign key to foo_type_lookup. Foo can either be bar or baz.
views.py
def add_foo(request):
action = '#'
errors = None
if request.method == 'POST':
form = FooForm(request.POST)
if form.is_valid():
form.save(commit=True)
return home(request)
else:
# The supplied form contained errors - just print them to the terminal.
errors = form.errors
else:
# If the request was not a POST, display the form to enter details.
form = FooForm()
# Bad form (or form details), no form supplied...
# Render the form with error messages (if any).
return render(request, 'foo/add_foo.html', {'form' : form, 'errors' : errors, 'action' : action})
forms.py
CONTACT_FOO_CHOICES = [[0,'Bar'],[1,'Baz']]
class FooForm(forms.ModelForm):
foo_type_lookup = forms.ChoiceField(widget=RadioSelect(), choices=CONTACT_FOO_CHOICES)
foo_name = forms.CharField(label='First Name', max_length=500, required=False)
class Meta:
model = foo
fields = ('foo_name','foo_type_lookup')
I have to iterate over the form object in my template so I can add a jQuery function when the radio buttons are changed. I find this pretty clunky, but I'm not sure of a more django way to accomplish this:
add_foo.html
<h2>add_foo.html</h2>
<form action="{{action}}" method="post" role="form">
{% csrf_token %}
{% for field in form %}
{% if field.auto_id = 'id_foo_type_lookup' %}
{% for choice in form.foo_type_lookup.field.choices %}
<li>
<label for="id_{{ field.html_name }}_{{ forloop.counter0 }}">
<input type="radio"
id="id_{{ field.html_name }}_{{ forloop.counter0 }}"
value="{{ choice.0 }}"
{% if choice.0 == '0' %}
checked="true"
{% endif %}
name="{{ field.html_name }}"
onchange="someFunction('id_{{ field.html_name }}_{{ forloop.counter0 }}')"/>
{{ choice.1 }}
</label>
</li>
{% endfor %}
{% else %}
<div class="formfield_err">{{ field.help_text }}</div>
<div id="{{ field.auto_id }}_container" >
<div class="formfield_divlbl">{{ field.label_tag }}
</div>
<div class="formfield_divfld">{{ field }}
{% if field.field.required %}
<span class="required">*</span>
{% endif %}
</div>
<div id="{{ field.auto_id }}_errors">{{ field.errors }}
</div>
</div><div class="clear" style="margin-bottom:12px;"></div>
{% endif %}
{% endfor %}
<input type="submit" value="Submit" />
</form>
I get the error:
Cannot assign "'0'": "foo.foo_type_lookup" must be a "foo_type_lookup" instance.
How do I layout the radio buttons for the type lookup to add onchange javascript and supply my ModelForm with an object of 'foo_type_lookup' so the data will save to the database?
A ChoiceField does not know it needs to coerce the provided value to a particular model instance.
Use a ModelChoiceField instead.
https://docs.djangoproject.com/en/1.7/ref/forms/fields/#modelchoicefield
Whoops, it seems you want some very specific display logic for your values hard coded into your python which may not necessarily equate to your string representations of your related model.
If so, override your form save to apply any coercion there before the real save gets called via super.
You can also manually apply any python logic via commit=False (I notice you already have that statement set to True and perhaps you were playing with the idea.)
obj = form.save(commit=false)
obj.foo_lookup_type = MyObject.objects.get(pk=form.cleaned_data['foo_lookup_type'])
obj.save()
I have this code of HTML (Django + Jinja) .
<div class="span10 well">
{% for k in values.chat %}
<label> Text : {{k.text}} </label>
<label> {{k.date_time}} </label>
{% endfor %}
<form action = "#" method = "POST" id = {{key}} name = "reply_form">
{% csrf_token %}
{{ form.as_p }}
<input type = "submit" value = "Sent" class="btn btn-primary">
</form>
</div>
Since, there will be many chats and correspondingly reply submit button and its key, I want that when I reply to a specific chat, it carries the key with itself and process the chat accordingly.
What I need is to append the url with the form id parameter. How can I achieve this?
You can create a hidden input field
<input type="hidden" name="chat_key" value="{{key}}">
This way you can track which chatroom the person is responding by setting the value to the id of the chatroom.
EDIT: Since you are using django, on the backend to get the value of the chat_key you can just do this:
chat_key = form.cleaned_data['chat_key']