Dynamically change smarty include file using Javascript - javascript

I have two tabs in my smarty file. In tab1 I have a dropdown menu it contains list of cities. I have list of templates based on city it contains details about the city. in Second tab i should show the relevant city template based on the dropdown selection.
For example:
Dropdown:
<select name='city' id='city' class="medium" style="float:left" onchange="setCityTpl(this);">
<option value=''></option>
{html_options options=$city_filter selected=$city.name}
</select>
If I select City 1 in dropdown menu
I should set the tpl name in the smarty include file as city1.tpl
<div id="tab2" class="tab-content" style="display: none; visibility: hidden; padding-top:0px">
{include file=city1.tpl}
</div>
if I select City 2 in dropdown menu
I should set the tpl name in the smarty include file as city2.tpl
<div id="tab2" class="tab-content" style="display: none; visibility: hidden; padding-top:0px">
{include file=city2.tpl}
</div>

You can load url from javascript. So I think if user selects City1 from Dropdown1, your JS will load city1.tpl and City2 will load city2.tpl
Or you can do the follow: the js script call an url (selected-city.php) with a POST/GET value with "city1" or "city2". The selected-city.php retrieves the selected-city.tpl with a parameter named selected (which taken from POST/GET) and your tpl:
<div id....>
{include file=${selected}.tpl}
</div ...>

smarty is a php-based template engine, which means that it runs on the server side, while javascript runs on the client side (the user's browser). So, before the user actually sees your page, the smarty templates have finished processing and any inclusions are already done.
To achieve what you want, one way would be to include all files and hide the respective html elements (with display:none for example). Then, based on the user's selection, you would show the elements you wish (the second drop down in your case

Related

Add an input box for each dropped file in dropzone

I have a drag drop box with dropzone.js. I allow multiple files upload (max 5 files at present). I have asked to add an ability for user to add description for each uploaded file.
The challenges I have:
Unable to determine how many files user dragged in zone
if I create text-boxes outside the zone, how do I tie them to each file correctly? I have set uploadMultiple to false and process one file at a time.
For example user uploaded 3 images of home, store & warehouse and 1 pdf and add description of Invoices, how do I ensure that Invoices doe not end up with home or store when processing that file?
I accomplished something like this by using a custom template for how Dropzone shows the file in the queue. I started with this example from the Dropzone author that explains how to use a custom template when displaying files in the queue. I expanded on the example by adding an extra form input to the template.
<div class="table table-striped" class="files" id="previews">
<div id="template" class="file-row">
<!-- This is used as the file preview template -->
<div>
<span class="preview"><img data-dz-thumbnail /></span>
</div>
<div>
<p class="name" data-dz-name></p>
<strong class="error text-danger" data-dz-errormessage></strong>
</div>
<!-- include a form field to collect the description -->
<div>
<label for="description">Description</label>
<textarea id="description"
data-name="description"
rows="3"></textarea>
</div>
<!-- remainder of template removed for brevity -->
</div>
</div>
Issue #1
When you add the form element, if you specify a name attribute, only the value from the form element associated with the last file will be submitted when the file uploads because you have multiple form elements all with the same name attribute.
To get around this, I did not include a name attribute but instead used a data-name attribute. Then I added the form element's value to the form data when the file got sent using this code:
myDropzone = new Dropzone('form#myuploadform')
myDropzone.on(
'sending',
function (file, xhr, formData) {
let description = file.previewElement.querySelector('textarea')
formData.append(description.getAttribute('data-name'),
description.value)
}
)
Issue #2
Because the id values are specified in the template, they will be the same value for every file added to the queue which violates the HTML spec since id values must be unique. Further since the for attribute of the LABEL element references the id of the TEXTAREA this also breaks accessibility because the second and subsequent LABELs will all reference the first TEXTAREA.
I fixed this by appending the UUID value Dropzone assigns to every file object to the id and for attributes as the file is being added to the queue, which is explained in this answer.

Disable JSF form field validation when submit

I have a <h:selectOneMenu>. Depending on what is selected will be shown one of the many <div>s related to the selection and will be hidden the others.
Each <div> has some <h:inputText> that write to different #ViewScoped beans. Some of this <div>s even write to the same properties in the beans.
Ex.
<div>
<h:outputLabel for="list" value="Items"/>
<div>
<h:message for="list"/>
<h:selectOneMenu id="list" value="#{bean.selectedItem}" >
<f:selectItem itemLabel="Select one"></f:selectItem>
<f:selectItems value="bean.someItemsList" />
</h:selectOneMenu>
</div>
</div>
<div id="item1">
<!-- some other input fields -->
<div>
<h:message for="item1input1"/>
<h:inputText id="item3input1" value="bean.thisIsTheSameProperty" />
</div>
</div>
<div id="item2">
<!-- some other input fields -->
</div>
<div id="item3">
<!-- some other input fields -->
<div>
<h:message for="item3input1"/>
<h:inputText id="item3input1" value="bean.thisIsTheSameProperty" />
</div>
</div>
The problem: When I select an item that will display a <div> (ex. <div id="item1">) and there is also another hidden <div> (ex. <div id="item3">) that writes to the same bean properties (ex. value="bean.thisIsTheSameProperty") and this properties are annotated with javax.validation.constraints.#NotNull, even I give a value to this input fields, when I submit the form, I think JSF runs also the hidden <div> (which normally has no input set).
What I see during debugging: When the form will be submited I see the setter of the bean will be called twice. The first time the bean properties will be set with the correct valeus I typed in but the second time the setter will be called with null values. So the validation will fail because of the #NotNull.
My assumption is that JSF tries to set the bean values twice, one for the input fields on the shown <div> and the second time for the hidden <div> (because they point to the same bean properties), but for the hidden bean there are not input fields set (they are null).
I show/hide the <div>s with jQuery depending on the item selected from the <h:selectOneMenu>.
Ex.
$('#item1').show();
$('#item1').hide();
$('#item2').show();
$('#item2').hide();
$('#item3').show();
$('#item3').hide();
Is there a way to say JSF to not consider the hidden <div>s at all?
You seem to be assuming that hidden inputs (hidden via CSS) are not submitted to the server. This assumption is wrong and it is a plain html thing btw, not JSF related at all.
See e.g. Stop an input field in a form from being submitted
But still, it would allow client-side manipulation via a browser developer tool to 'attack' you application. JSF, contrary to all the hyped javascript UI frameworks is a full grown 'MVC framework' that has build in protection against client-side manipulation/tampering and CSRF, XSS for which you'd need OWASP related functionality in other framework. (That and other things makes JSF (with PrimeFaces, OmniFaces and DeltaSpike) for me still a great framework to quickly develop business oriented applications.)
You'd better use ajax to conditionally render one div or the other but you cannot 'update' the divs when they are defined like you have them.
See also:
Ajax update/render does not work on a component which has rendered attribute
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
The answer from #Kukeltje and comment from #drkunibar worked for me.
I modified it a little.
Actual solution:
$('#myForm').submit(function() {
if($('#list').find(':selected').val() === 'itemOption1') {
$('item3').remove();
} else if($('#list').find(':selected').val() === 'itemOption3') {
$('item1').remove();
}
});
I check to see which option is selected. If option1 is selected then I remove the div with iditem3 from the DOM, or else if the option3 is selected then I remove the div with iditem1 from the DOM.
In this way the binding bean.thisIsTheSameProperty is transmitted only one and the values will not be overriden.
Thank you.

Alternative for g:select (multiple values)

I have a Domain Class Project with a one-to-many property users :
static hasMany = [users: User]
In my scaffolding code the view is created with:
<div class="fieldcontain ${hasErrors(bean: projectInstance, field: 'users', 'error')} ">
<label for="users">
<g:message code="project.users.label" default="Users" />
</label>
<g:select name="users" from="${usermanagement.User.list()}" multiple="multiple" optionKey="id" size="5" value="${projectInstance?.users*.id}" class="many-to-many"/>
</div>
This results in a simple list where I can select multiple users. The user list is expected to be quite big so this selection isn't really viable. Is there a simple way in grails to do this a bit more comfortable? The best solution I can imagine would be a list with an autocomplete searchform and a second list where the selected entries are displayed.
I don't think that there is an easy way to do this and that I probably have to use javascript or jquery (autocomplete etc.)
Any help improving my current status (selection from huge list via ctrl + click)
would be very appreciated.
There is a jQuery plugin called Chosen that will do what you are wanting, it supports multiple selections. I have a use case much like yours in one of my apps and Chosen worked out great:
http://harvesthq.github.io/chosen/
A possible solution is using some javascript based stuff like boostrap select2 or Kendo UI Multiselect. They are based on a html select box that unobtrusively enhanced the selection model of a this html element. So there is no real javascript code to implement, since the selection model for the html form stays the same as with disabled javascript.

AngularJS SELECT doesn't validate properly

This is an AngularJS application (1.2.16). I browse to a dialog to edit some item. One of the controls is a multi-SELECT with the following visible values:
incident
work order
These visible values correspond to the following data values:
INCIDENT
WORK_ORDER
This is done through using the ng-options=" ... as ... for ... in ... " pattern, using an enumeration:
var FlexFieldSubjectTypeEnum = {
INCIDENT:{name:"INCIDENT", description:"incident"},
WORK_ORDER:{name:"WORK_ORDER", description:"work order"}
}
If have a form pretty much as follows:
<form ng-submit="save(formName)" name="formName" class="form-horizontal">
...
<div class="control-group">
<label class="control-label">Subject type:</label>
<div class="controls">
<select name="subjectType"
ng-options="type.name as type.description for type in getEnumAsArray('FlexFieldSubjectTypeEnum') | orderBy:'name'"
ng-model="entity.subjectType"
required></select>
</div>
</div>
Now, if the dialog loads the item ($scope.entity) from the backend and entity.subjectType is set to the first item in the list, the form validation marks it as unset. I have many other dialogs with similar constructs and have not seen this problem anywhere else.
If the item returned from the backend points to the second item (WORK_ORDER), this is nicely represented in the SELECT ("work order") and there is no validation error.
The problem does exist equally when using required or ng-required="true".
The problem does not exist if I remove the required attribute, but then the field also suddenly becomes optional, which is not what I wanted.
Your help much appreciated!
Almost a month later, with meanwhile an upgrade from Bootstrap v2.2.2 to v3.1.1 the problem disappeared.

Binding an event after a page reload and creating new html element using Knockout.js, HTML and JS only?

I am new to knockout libraries and we are working on an iPad web app. The situation is when a user check a checkbox in a HTML page, we need to add a new div in the page with some text boxes in it and remove it when he uncheck those.
Point to be noted: the new div is binded to data that needs to be default loaded in the text box or selects.
Its an iPad web app. It uses Knockout, jQuery, JS and HTML with MVVM.
The question is, can Knockout bind html elements after the page load, as custom handler works/register themselves only during init and can a dynamic div be created using js and html, if yes then how to put it between two static divs?
You can bind elements after page load using ko.applyBindings(viewModel, ElementSelector), like so:
ko.applyBindings(myModel, $("#myDiv"));
However, this isn't something you generally want to do. It's much easier to use the If binding in Knockout, which will dynamically add or remove child elements from the page.
<input type="checkbox" data-bind='checked: showChild' />
<div id="container" data-bind="if: showChild">
<!-- stuff here will only be generated if the checkbox is selected -->
</div>
If you had multiple different elements to show based on a value of something, say a select list, you could use the template feature instead:
//viewmodel properties
self.Options = ko.observableArray(["Name", "Age", "Height"])
self.TemplateToUse = ko.observable()
//html
<select data-bind="options: Options, value: TemplateToUse">
</select>
<div data-bind='template: { name: TemplateToUse }'>
<!-- template whose name is selected value -->
</div>
//templates
<script type="text/html" id="Age">
<span>Age</span>
</script>
<script type="text/html" id="Name">
<span>Name</span>
</script>
<script type="text/html" id="Height">
<span>Height</span>
</script>

Categories