I have created an ordering system which has a page that allows the end user to place/add to an order and then move to the next page to review the entire order.
I want to be able to have the user move back to the order page from the review order page and see the quantity that was just added/placed...so if I order 2 of widget A, I move to the review page and see that I have an order with 2 A widgets for a particular cost; I then move back to the order page and the quantity of 2 should still be visible to the end user and displayed with Widget A.
I have worked all of this out UNTIL I try to redisplay the Order page and its associated fields.
I get a Value cannot be null or empty error; I realize the meaning of this error and I have stepped through the code and can see that I have data!! I see nothing that is null nor empty that should not be.
What am I doing wrong?
My code:
menuIndex = 0;
intMenuTable1 = 3;
foreach (var menu_item in Model.OrderMenu)
{
if (menuIndex < intMenuTable1)
{
<tr>
<td align="center">
#Html.TextBoxFor(m => m.OrderMenu[menuIndex].Quantity, new { #class = "form-control", #style = "width:50px; height:50px;text-align:center; margin-top:50px; margin-left:10px;"})
#Html.TextBoxFor(m => m.OrderMenu[menuIndex].ID)
#Html.TextBoxFor(m => m.OrderMenu[menuIndex].ProductPrice) - **error is here**
</td>
<td align="center">
<img id="imgProduct" src=#Url.Content(#menu_item.ProductImage) />
</td>
</tr>
}
}
The error was actually BELOW the line that was coming across as an error.
I was not passing all of the model elements that I needed to recreate the view, hence the NULL values.
Related
I'm in the middle of wire-framing out some basic forms and I'm hitting an unexpected 405 Method Not Allowed blocker.
Basically I have some html in a jinja template looking like...
<!--Select File Y-->
<tr>
<td>File Y</td>
<td>{{form.pathY }}</td>
<td><input type=file name=browse ></td>
<td><button onclick="window.location.href='{{ url_for( 'dataTablePage' , table='Y' ) }}';">Display Table Y</button></td>
</tr>
<tr>
<td/>
<td/>
<td/>
<td>View Merged Data</td>
</tr>
In the DOM this is rendering more or less what I'd expect as with the location.href = '/DataTable/Y/'
However when I click the button I wind up here in the 405 Method Not Allowed page.
On the other hand the redirect works as expected when I redirect from anchors with url_for. What's the deal with using url_for in in a button's onclick redirection?
Not sure if it matters, but here's the route I'm connecting to...
#app.route('/DataTable/<table>/')
def dataTablePage(table) :
"""
Takes the user to the Table View corresponding to the given table parameter
"""
table == "X" :
dfTable = DataFrame( data = {"X1":[1,2,3] , "X2":[2,3,4]} )
elif table == "Y" :
dfTable = DataFrame( data = {"Y1":[1,2,3,4,5] , "Y2":[2,3,4,5,6]} )
elif table == "Merged" :
dfTable = DataFrame( data = {"M1":[1,2] , "M2":[2,3]} )
else :
redirect( url_for('error') )
return render_template( 'dataTable.html' , filePath="x.csv" , headers=dfTable.columns.values.tolist() , table=dfTable.iterrows() )
This is a problem with your HTML actually, the default "type" of button is:
The missing value default is the Submit Button state.
And since you have not specified the button's type, it simply tries to submit the form, which leads to 405 problem.
Change your button type to "button" and it should work as expected:
<button type="button" onclick="window.location.href='{{ url_for( 'dataTablePage' , table='Y' ) }}';">Display Table Y</button>
Imagine you have a table displaying a list of books (like the index does) and you want to make changes in a column called "Sold" (a checkbox for example). So once you finish "Checking" the books you have sold, you click a Button to save! How do you send back that list to the controller and update it?
So, the code is something like this, in the controller:
def aMethod(){
...
[bookInstanceList: myBookList]
}
In the GSP:
<g:each in="${bookInstanceList}" status="i" var="bookInstance">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td><g:link action="show" id="${bookInstance.id}">${fieldValue(bean: bookInstance, field: "author")}</g:link></td>
<td><g:checkBox name="sold" value="${bookInstance?.sold}" /></td>
<td>
</tr>
</g:each>
The idea is with the checkbox let the user change the "Sold" value from that book, and then make a submit with a Button. How can I save my new bookInstanceList?
Thank you very much
There is a simple sample app at https://github.com/jeffbrown/books which shows one way you could do this. Run the app, open the default index page, click on the link and that will take you to a page where you can click checkboxes and update the library of books.
Files of interest are https://github.com/jeffbrown/books/blob/master/grails-app/controllers/com/demo/BookController.groovy and https://github.com/jeffbrown/books/blob/master/grails-app/views/book/index.gsp.
I hope that helps.
I've removed some of the markup for brevity and to bring focus to the important bits. This is one way of doing it without relying on Javascript and what do you know, it is pure grails. Never say never, #rmlan.
<g:form action="updateSold" controller="book">
<table>
<tbody>
<g:each in="${bookInstanceList}" status="i" var="bookInstance">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td><g:link action="show" id="${bookInstance.id}">${fieldValue(bean: bookInstance, field: "title")}</g:link></td>
<td>
<g:checkBox name="sold" value="${bookInstance.sold}" />
<g:hiddenField name="id" value="${bookInstance.id}" />
</td>
</tr>
</g:each>
</tbody>
</table>
<g:submitButton name="updateSold" value="Update" />
</g:form>
This is the controller action:
def updateSold() {
def solds = params.list('sold')
def ids = params.list('id')
ids.eachWithIndex { id, idx ->
if (solds[idx]) {
// the book's sold has been checked, so update it to TRUE
} else {
// the books sold has not been checked, so update it to FALSE
}
}
}
I have a many to many relationship between forms and events, in a list using a join table and when I display the data in edit mode I show each item in its own dropdown in a table as opposed to one multi select dropdown list. I also have a little jQuery in there to add extra dropdowns in if I want to add more items, My question is, how do I then save back this set of "events", in order? Code is as follows: -
Initial _form.gsp to load all linked events for the form: -
<table id="eventList">
<g:each in="${formInstance?.events}" status = "i" var="item">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td>
<label></label>
<g:select name="event_${i}" from="${framework.Event.list()}" required="required" optionKey="id" value="${item.id}" />
</td>
</tr>
</g:each>
</table>
Additional objects are added with this gsp
<tr class="${((newRow+1) % 2) == 0 ? 'even' : 'odd'}">
<td>
<label></label>
<g:select name="event_${newRow-1}" from="${framework.Event.list()}" required="required" optionKey="id" />
</td>
</tr>
The save button currently is as such: -
<g:actionSubmit class="save" action="update" value="${message(code: 'default.button.update.label', default: 'Update')}" />
And the Update action is unchanged from the one generated automatically from the domain setup. How do I get the save to recognise the new fields added? Currently hitting save does to the "events", even if I change the order...
Domain Classes are as such
import java.util.List;
class Form {
static constraints = {
formDesc(blank:false,maxSize:100,unique: true)
}
static mapping = {
table "form"
version false
columns{
id column:"form_id"
formDesc column:"description"
testscenarios joinTable:[name:"lnk_scenario_form",key:'form_id']
events joinTable:[name:"lnk_form_event",key:'form_id']
}
}
String formDesc
List events
static hasMany = [testscenarios:TestScenario, events:Event]
static belongsTo = fartframework.TestScenario
String toString (){
"${formDesc}"
}
}
And
class Event {
static constraints = {
eventTypeID()
eventOrder()
objectID()
testDataID()
}
static mapping = {
table "event_form"
version false
columns{
id column:"event_form_id"
eventTypeID column:"event_id"
eventOrder column:"event_order"
testDataID column:"test_data_id"
objectID column:"object_id"
forms joinTable:[name:"lnk_form_event", key:'event_id']
}
}
EventType eventTypeID
Integer eventOrder
TestData testDataID
Object objectID
static hasMany = [forms:Form]
static belongsTo = fartframework.Form
String toString (){
"${eventTypeID}"
}
}
Turns out this was because my link table had a primary key set on both the form_id AND event_id combination columns, which I don't care about as I WANT to be able to have duplicates in there (as its the order that's more important), removing these primary key values on the table solved the problem!
I do still have the issue that if I now add/remove a bunch of times I get problems with identical names and the issues that represents, but I can work round that one with some jquery hacking (I hope)...
I have a question regarding how to fetch a value from list item to a MultiLine textBox.
I have tried alot. First time it gave the correct data.
and still it gives the correct data however it also fetches the div tags along with the data.
Any thoughts if any please help.
Here is my code:
Register.aspx
<tr>
<td>
<asp:Label ID="Label3" runat="server" Text="Prerequisite"></asp:Label>
</td>
<td>
<asp:TextBox ID="TxtPrerequisite1" runat="server" TextMode="MultiLine" ReadOnly="true"></asp:TextBox>
</td>
</tr>
Register.aspx.cs
string oPrerequisite = null;
SPSite oSPSiteCollection = SPContext.Current.Site;
SPWeb oSPWeb = SPContext.Current.Web;
SPList oSPList1 = oSPWeb.Lists["Scheduled Courses"];
SPListItemCollection oItemCollectionCourse = oSPList1.Items;
foreach (SPListItem ospListItemCourse in oItemCollectionCourse)
{
oPrerequisite = ospListItemCourse["Prerequisite"].ToString();
TxtPrerequisite1.Text = oPrerequisite;
}
The actual out put i am getting is :
<div class="ExternalClassEAA502F55D7B4F9BBA347E2137621D8A"><p> Correct Value is here >div </p></div>
Where as the expected output is:
Correct Value is here
How can I remove the tag from the correct answer so I have only value.
Try SPHttpUtility.ConvertSimpleHtmlToText
TxtPrerequisite1.Text =
SPHttpUtility.ConvertSimpleHtmlToText(oPrerequisite, oPrerequisite.Length);
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! ;)