Tabular form validation without submitting - oracle-apex

In APEX 3.2, I want to be able to run JavaScript validations to check the data entered and display the appropriate message above each row in the tabular form.
I'm not sure how this would work given that it is a tabular form and the user will be able to add/delete rows.
Appreciate any ideas or suggestions.
Thanks.

Okay, doing some javascript validations on tabular forms is a bit complex, and you need to know what you're doing.
First off, you will need to know the ids or names of the elements you wish to check. As you may know, elements in tabular forms are stored in arrays in apex on submit, and are accessed through apex_application.g_f01/g_f02/...
This is reflected in the html code, and the generated elements also have the attribute 'name' set to the column they belong to. The id also holds the column, plus the rowindex. Warning though, this id is only generated like this when the item is created 'implicitly', ie you did not write your query with apex_item calls (apex_item.textbox(...)).
Another but is that only fields of which the state is saved will have an array column defined. An item which you'd only show as 'display only', will not be generated with an input tag, and will just be held as text in a td tag.
All by all, when you know that, the next steps should be straightforward enough. Take a look at the page source, and take a note of the elements you wish to target. For example, i went for the job field.
<tr class="highlight-row">
<td headers="CHECK$01" class="data"><label for="f01_0003" class="hideMeButHearMe">Select Row</label><input type="checkbox" name="f01" value="3" class="row-selector" id="f01_0003" /></td>
<td headers="EMPNO_DISPLAY" class="data">7782</td>
<td headers="ENAME" class="data"><label for="f03_0003" class="hideMeButHearMe">Ename</label><input type="text" name="f03" size="12" maxlength="2000" value="CLARK" id="f03_0003" /></td>
<td headers="JOB" class="data"><label for="f04_0003" class="hideMeButHearMe">Job</label><input type="text" name="f04" size="12" maxlength="2000" value="MANAGER" id="f04_0003" /></td>
<td headers="HIREDATE" class="data"><label for="f05_0003" class="hideMeButHearMe">Hiredate</label><span style="white-space: nowrap;"><input type="text" id="f05_0003" name="f05" maxlength="2000" size="12" value="09-JUN-81" autocomplete="off"></span></td>
<td headers="SAL" class="data">
<label for="f06_0003" class="hideMeButHearMe">Sal</label><input type="text" name="f06" size="16" maxlength="2000" value="2450" id="f06_0003" />
<input type="hidden" name="f02" value="7782" id="f02_0003" />
<input type="hidden" id="fcs_0003" name="fcs" value="19BD045E01D6BA148B4DEF9DDC8B21B7">
<input type="hidden" id="frowid_0003" name="frowid" value="AAuDjIABFAAAACTAAC" />
<input type="hidden" id="fcud_0003" name="fcud" value="U" />
</td>
</tr>
In the javascript section of the page i then added the following 2 functions.
validate_job does the validation of just one field, the element elJob. The validation i used is just very basic, it's up to you to determine just how complex you want it.
If you want to reference other fields in the same row here, you can do several things: extract the rowindex from the id, if you have it. If it doesn't hold the it, get the parent TR, and then use .children("input[name='f##'") to get an input element in the same row. Or if you need the value of an item which does not save state at all, you'll need to get the TR element, and then find the TD which contains the element you need through the headers attribute, which holds the column name.
function validate_job(elJob){
var sJob = $v(elJob).toUpperCase();
$(elJob).val(sJob);
//do your validations for the field job here
if(sJob=="MANAGER"){
$(elJob).css({"border-color":"red"});
alert("invalid value!");
//depends what you want to do now:
//keep the focus on this element? Set a flag an error occured? Store the error?
return false;
} else {
$(elJob).css({"border-color":""});
alert("value ok");
};
};
Call bind_validations onload. If you allow rows to be created, bind a click event to the addrow button and call bind_validations.
function bind_validations(){
//f01 : row selector
//f03 : ename
//f04 : job
//f05 : hiredate
//f06 : sal
//each input element with attribute name with value f04
//blur event is when the user leaves the field, fe tab out, or even click apply changes
//much like how when-validate-item behaved in forms
$("input[name='f04']").blur(function(){validate_job(this);});
};
Just a proper warning though. I've used javascript validations in some apps so far, but i knew they were only going to be used by a small number of people, and then only internally. It was only one field, with some validations. I made the cursor refocus on the field when the validation failed, so they couldn't jump to the next record and change that aswell. Either a valid value was given, or they reloaded the page or canceled the action. Set up like this, they can't press apply changes either, as the blur event would also fire, validating the field.
When your audience is larger, it gets a bit more iffy: what i javascript is disabled? What if they find some way around? Wizzkids?
I still like the immediate feedback it gives, but in a more critical environment i'd also use the server-side validations. To do this, you need a validation of the type "function returning error text". Check out this page for an example, or this one for some usefull tips (at least for pre 4.0!). Also: apex 4.1 really improves a lot on tabular form validations! ;)

Related

Form Validation On Frontend or Backend Django

I have an HTML form with a date field:
<input type="date" class="form-control" placeholder="Date" name="date" autocomplete="off" required>
Before submitted the form, I want to ensure that the date that was entered is greater than the current date. If it is older, then I want to show a custom form validation to say something like, "You must enter a date past today.".
Do you suggest I do this validation on the backend or the frontend? Thanks!!
I think you're better off doing in within django forms. The reason is, if you do it in the front-end, you'll have to repeat the code when applying this property elsewhere.

How to add extra option to cfselect other than default?

I have a drop down where I show the options of a query and the default
is from a specific column.
I want to add a extra option 'None' to the list. How would I do this?
<th>Image</th>
<td>
<cfselect name="image" query="UnionQuery2" value="name" display="name">
<option>#tesing11#</option>
</cfselect>
</td>
As per the documentation of cfselect, use the queryPosition attribute. The docs even have an example showing exactly what you want to do.

How to make a plone view that inserts other smaller views of content items?

I think this should be simple. I have a folderish TTW dexterity content item (a drop box) that contains folderish TTW dexterity items (proposals). Each proposal contains TTW dexterity reviews that have fields I want to summarize.
I can easily make a view that generates a table as indicated below for any proposal with simple modifications to the folderlisting view:
[review1 link] [criterion_1 value] [criterion-2 value]...
[review2 link] [criterion_1 value] [criterion-2 value]...
.
.
I can also generate a working table view for a drop box by modifying the folderlisting view:
[proposal1 link] [column I would like to insert the above table in for this proposal]
[proposal2 link] [column I would like to insert the above table in for this proposal]
.
.
My problem is I cannot figure out how to insert the first table into the cells in the second column of the second table. I've tried two things:
Within the view template for the dropbox listing, I tried duplicating the repeat macro of the listingmacro, giving it and all its variables new names to have it iterate on each proposal. This easily accesses all of the Dublin core schemata for each review, but I cannot get access to the dexterity fields. Everything I have tried (things that work when generating the first table) yield LocationError and AttributeError warnings. Somehow when I go down one level I lose some of the information necessary for the view template to find everything. Any suggestions?
I've also tried accessing the listing macro for the proposal, with calls like <metal use-macro="item/first_table_template_name/listing"/>. Is this even partially the right approach? It gives no errors, but also does not insert anything into my page.
Thanks.
This solution is loosely based on the examples provided by kuel: https://github.com/plone/Products.CMFPlone/blob/854be6e30d1905a7bb0f20c66fbc1ba1f628eb1b/Products/CMFPlone/skins/plone_content/folder_full_view.pt and https://github.com/plone/Products.CMFPlone/blob/b94584e2b1231c44aa34dc2beb1ed9b0c9b9e5da/Products/CMFPlone/skins/plone_content/folder_full_view_item.pt. --Thank you.
The way I found easiest to create and debug this was:
Create a minimalist template from the plone standard template folder_listing.pt which makes just the table of summarized review data for a single proposal. The template is just for a table, no header info or any other slots. This is a stripped version, but there is nothing above the first statement. A key statement that allowed access to the fields were of the form:
python: item.getObject().restrictedTraverse('criterion_1')
The table template:
<table class="review_summary listing">
<tbody><tr class="column_labels"><th>Review</th><th>Scholarly Merit</th><th>Benefits to Student</th><th>Clarity</th><th>Sum</th></tr>
<metal:listingmacro define-macro="listing">
<tal:foldercontents define="contentFilter contentFilter|request/contentFilter|nothing;
contentFilter python:contentFilter and dict(contentFilter) or {};
I kept all the standard definitions from the original template.
I have just removed them for brevity.
plone_view context/##plone;">
The following tal:sum is where I did some math on my data. If you are
not manipulating the data this would not be needed. Note that I am only
looking at the first character of the choice field.
<tal:sum define="c1_list python:[int(temp.getObject().restrictedTraverse('criterion_1')[0])
for temp in batch if temp.portal_type=='ug_small_grants_review'];
c1_length python: test(len(c1_list)<1,-1,len(c1_list));
c2_list python:[int(temp.getObject().restrictedTraverse('criterion_2')[0])
for temp in batch if temp.portal_type=='ug_small_grants_review'];
c2_length python: test(len(c2_list)<1,-1,len(c2_list));
c1_avg python: round(float(sum(c1_list))/c1_length,2);
c2_avg python: round(float(sum(c2_list))/c2_length,2);
avg_sum python: c1_avg+c2_avg;
">
<tal:listing condition="batch">
<dl metal:define-slot="entries">
<tal:entry tal:repeat="item batch" metal:define-macro="entries">
<tal:block tal:define="item_url item/getURL|item/absolute_url;
item_id item/getId|item/id;
Again, this is the standard define from the folder_listing.pt
but I've left out most of it to save space here.
item_samedate python: (item_end - item_start < 1) if item_type == 'Event' else False;">
<metal:block define-slot="entry"
The following condition is key if you can have things
other than reviews within a proposal. Make sure the
item_type is proper for your review/item.
tal:condition="python: item_type=='ug_small_grants_review'">
<tr class="review_entry"><td class="entry_info">
<dt metal:define-macro="listitem"
tal:attributes="class python:test(item_type == 'Event', 'vevent', '')">
I kept all the standard stuff from folder_listing.pt here.
</dt>
<dd tal:condition="item_description">
</dd>
</td>
The following tal:comp block is used to calculate values
across the rows because we do not know the index of the
item the way the batch is iterated.
<tal:comp define = "crit_1 python: item.getObject().restrictedTraverse('criterion_1')[0];
crit_2 python: item.getObject().restrictedTraverse('criterion_2')[0];
">
<td tal:content="structure crit_1"># here</td>
<td tal:content="structure crit_2"># here</td>
<td tal:content="structure python: int(crit_1)+int(crit_2)"># here</td>
</tal:comp>
</tr>
</metal:block>
</tal:block>
</tal:entry>
</dl>
<tr>
<th>Average</th>
<td tal:content="structure c1_avg"># here</td>
<td tal:content="structure c2_avg"># here</td>
<td tal:content="structure avg_sum"># here</td>
</tr>
</tal:listing>
</tal:sum>
<metal:empty metal:define-slot="no_items_in_listing">
<p class="discreet"
tal:condition="not: folderContents"
i18n:translate="description_no_items_in_folder">
There are currently no items in this folder.
</p>
</metal:empty>
</tal:foldercontents>
</metal:listingmacro>
</tbody></table>
Create another listing template that calls this one to fill the appropriate table cell. Again, I used a modification of the folder_listing.pt. Basically within the repeat block I put the following statement in the second column of the table:
This belongs right after the </dd> tag ending the normal item listing.
</td> <td class="review_summary">
<div tal:replace="structure python:item.getObject().ug_small_grant_review_summary_table()" />
</td>
Note that "ug_small_grant_review_summary_table" is the name I gave to the template shown in more detail above.

How to add and save entry in dropdown listbox using coldfusion

Id like to make a drop down list box where in at the end of the list, an option "Enter New housing", that if selected there will be a message box then it will automatically saves on the database and refreshes the object.
Im a beginner and this is what ive started:
<cfquery name="housingsel" datasource=" " dbtype=" ">
select rtrim(housing_name) as housing, housingid as housingid from housing order by housing
</cfquery>
<!---<cfquery name="housingins" datasource=" " dbtype=" ">
insert into housing (housingid,housing_name) values (1,'Tierra Pura Housing')
</cfquery>--->
<body>
<div class="container">
<div class="content">
<h1>Housing</h1>
<table width="300" bgcolor="#FFFFFF" cellpadding="2" cellspacing="0" border="0">
<cfform action="de_housing.cfm" method="POST">
<tr><td height="20" class="lbl" align="right">Housing</td><td>
<select name="housingcat">
<CFOUTPUT QUERY="housingsel">
<OPTION VALUE="#housingid#">#housing#</OPTION>
</CFOUTPUT>
<option value="new">Enter New Housing</option>
</select>
</td></tr>
<tr><td height="20" class="lbl"></td><td align="left">
</td></tr>
</cfform>
</table>
Please help!
Thanks!
First off, avoid cfform at all costs. It will not help you. See https://github.com/cfjedimaster/ColdFusion-UI-the-Right-Way for reasons why and examples of how to do stuff the right way.
That being said, what you want to do isn't difficult. Let's break it down.
> "Id like to make a drop down list box where in at the end of the list, an option "Enter New housing", that if selected "
Using jQuery, you would add a change handler to your dropdown. In that change handler, you can get the selected index of the drop down. If that index is equal to the length of the options, then the user has picked the last one.
> "there will be a message box"
You have a few choices here. One simple, but not pretty way, is to use the built in confirm option. It has a simple modal box API that the user can type in. There are pretty options, like jQuery UI dialogs, but the confirm option is super simple. I'd recommend starting there.
> "automatically saves on the database"
So, you will know when a user enters a value into the confirm. Take that and use jQuery to do an XHR (Ajax) hit to your code. You will need to write CF code to respond to this request and insert it into the db. Not too difficult and it has been shown many places elsewhere. I'd also add logic to check for dupes.
> "refreshes the object"
When you do a XHR in jQuery, you know when the server is done doing crap, so in the response handler, you can add a new option to the drop down. This too has been done many times before, just Google for adding an option to a drop down. (You will probably end up back here.)

CFdump and Bootstrap tooltips fight each other

I attach Bootstrap tooltips via
$("[title]").tooltip({ html: true });
When I use a <cfdump>, title tags are attached all over the place. The start of the <cfdump> html looks like this
<table class="cfdump_struct">
<tr><th class="struct" colspan="2" onClick="cfdump_toggleTable(this);" style="cursor:pointer;" title="click to collapse">struct</th></tr>
<tr>
<td class="struct" onClick="cfdump_toggleRow(this);" style="cursor:pointer;" title="click to collapse">Cause</td>
<td>
Is there a way to keep, the two from stepping on eachother?
You shouldn't care because cfdump shouldn't be used in production, however you could just reduce the array returned by the jQuery selector. Not sure if this is the best way to do it, but it works:
$("[title]").filter(function(){
return ($(this).closest(".cfdump_struct").length == 0);
}).tooltip({ html: true });
It runs the filter function for each item in the array returned by the selector. If it is within the CFDUMP table (signified by the .cfdump_struct class) it will not return it. You will have to extend this to other cfdump types (queries, etc) but this should get you started.
Again, it really shouldn't matter since you shouldn't be using cfdump in production code anyway.
You can see this in action here: http://jsfiddle.net/seancoyne/rc7TL/