I am newbie to Lift and I have a question on using bind, Ajax in Lift.
I want to create three dropdown menus using Ajax in a dynamic fashion. I use "Address" as an example to describe what I am trying to achieve. At fist, I only have to display "Country" menu with default set to "None". The user at this point can choose to submit if she wishes to and the address is taken as default. If not, she can provide the precise address. Once she selects the country, the "State" menu should get displayed, and once she selects "State", the "County" menu should be displayed.
With the help of lift demo examples, I tried to create static menus as follow. I created three snippets <select:country/>, <select:state/>, <select:county/> in my .html file and in the scala code, I bind as follows:
bind("select", xhtml,
"system" -> select(Address.countries.map(s => (s,s)),
Full(country), s => country = s, "onchange" -> ajaxCall(JE.JsRaw("this.value"),s => After(200, replaceCounty(s))).toJsCmd),
"state" -> stateChoice(country) % ("id" -> "state_select"),
"county" -> countyChoice(state) % ("id" -> "county_select"),
"submit" -> submit(?("Go!"),()=>Log.info("Country: "+country+" State: "+state + " County: "+ county)
The corresponding replaceCounty, stateChoice, countyChoice are all defined in my class. However, when the country is selected, only the state is refreshed through Ajax call and not the county.
Q1) Is there a way to refresh both the menus based on the country menu?
Q2) How to create the menu's dynamically as I explained earlier?
There is an excellent example code that does just this available at:
http://demo.liftweb.net/ajax-form
If you want to update multiple dropdowns as a result of an AJAX update, you'll want to return something like:
ReplaceOptions(...) & ReplaceOptions(...)
Use SHtml.ajaxSelect for your first select, and static elements for the other two. When the first select changes, you'll return javascript to populate the next select with the result of another SHtml.ajaxSelect call.
def countrySelect : NodeSeq = {
val countryOptions = List(("",""),("AR","AR"))
SHtml.ajaxSelect(countryOptions, Empty, { selectedCountry =>
val stateOptions = buildStateOptions(selectedCountry)
SetHtml("state-select", SHtml.ajaxSelect(stateOptions, Empty, { selectedState =>
// setup the county options here.
}))
})
}
bind(namespace, in,
"country" -> countrySelect,
"state" -> <select id="state-select"/>,
"county" -> <select id="county-select"/>)
In the callbacks for #ajaxSelect you'll probably want to save the values of whatever has been selected, but this is the general approach I'd take.
Related
I have an IG region where I disabled the toolbar and created my custom search item.
I want user to be able to type the first three characters of a name on the search item (named P8_SEARCH) and the IG report will only show the name(s) that starts with those 3 characters.
This should happen without clicking any button. The IG report query is shown below:
select member_id, first_name, last_name , address, dob, home_phone, cell_phone,
email_address from member_profile where first_name like '%'||:P8_SEARCH||'%';
I also created dynamic action with key release event and True action Execute JavaScript Code shown below:
var keyPressCount=0;
$("#P8_SEARCH").on("keypress", () => {
if (keyPressCount < 2) {
keyPressCount++;
} else {
$s("P8_SEARCH", apex.item( "P8_SEARCH" ).getValue());
}
})
How can I achieve this without submitting the page? I will appreciate any suggestion. Example:
Set an static_id for your IG region, in the dynamic action add apex.region("yourStaticId").refresh();to your JS code, this will refresh only the region.
something like this:
var keyPressCount=0;
$("#P8_SEARCH").on("keypress", () => {
if (keyPressCount < 2) {
keyPressCount++;
} else {
$s("P8_SEARCH", apex.item( "P8_SEARCH" ).getValue());
apex.region("yourStaticId").refresh();
}
})
If the search items are stored in an associated table, my idea is that you could associate a PL/SQL expression to execute using a Process. This process could be executed on a custom action.
Another idea is that you associate the dynamic action with a hidden button press, and make the JavaScript code click on the button. Then, you can 'simulate' the existence of a trigger for your dynamic action with key release event
What do you think?
I have a custom edit template for kendo scheduler.
Below all the controls to set dates and the recurrence rule I have a button.
Pressing the button loads a list of people available for that appointment.
To get that list, I am checking conflicts in future visits and I'm checking against a people availability table to make sure they are available on those dates.
All the code works fine except I cannot get the recurrence rule before the Save button is pressed and the data is transported to the server.
The recurrenceRule property is blank even though all the selections are made before pressing my button.
It seems kendo scheduler formats that recurrence rule when you press the save button and then populates the model and transports it to the server.
I could write my own Recurrence Rule by reading the widgets in the kendo recurrence editor control but they didn't put an Id's on the widgets which makes them hard to get. I think you can use css selectors but I haven't done anything like that and would rather not write my own recurrence editor.
Does anyone know how to get the recurrence rule while in the edit template before pressing Save?
FLOW:
1) set start and end date, and recurrence pattern in kendo recurrence editor
2) press button on edit template form to load available employees
--- I need the recurrence rule here.
On the server side I expand the appointment to all it's occurrences
and then I check each potential visit against the employee schedule
3) select one of the employees and save the record.
--- I can't do the check here because the employee has to be selected before saving the record and I only want to provide a list of available employees -- before save.
I tried many things including this:
var recurEditor = $("#RecurrenceRule").data("kendoRecurrenceEditor");
var recurrenceRule = recurEditor.options.recurrenceRule;
alert("recurrenceRule: " + recurrenceRule);
But no luck...
Here's the solution. I knew if I posted the question here, after 2 days of trying to figure it out, that I'd find the solution. Maybe this will help someone else.
On the handler for my button to load available employees, I have this code:
var ruleEditor = $('[id="RecurrenceRule"]').getKendoRecurrenceEditor();
if (ruleEditor) {
vRecurRuleValue = ruleEditor.value();
alert("vRecurRuleValue = " + vRecurRuleValue);
}
My recurrence editor is defined in my edit template as so:
#(Html.Kendo().RecurrenceEditorFor(model => model.RecurrenceRule).HtmlAttributes(new { data_bind = "value:recurrenceRule", data_role = "recurrenceEditor" } ))
And my employee dropdown has a filter as follows:
<div id="EmpAssignedDropdownlist" class="k-edit-field" style="visibility:hidden;">
#(Html.Kendo().DropDownListFor(m => m.VisitEmployeeM.UserId)
.AutoBind(false)
.Text("Please Select") //used to prevent initial datasource.read as AutoBind doesn't work
.DataTextField("name")
.DataValueField("id")
.ValuePrimitive(true)
.OptionLabel(#Localizer["Please Select"].Value)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetEmployeesAvailableForPotentialVisit", "DropDownList").Data("filterAvailableEmployeesNoVisitYet");
}).ServerFiltering(true);
})
)
</div>
the javascript function "filterAvailableEmployeesNoVisitYet" passes the recurrence rule and other data I need to check for conflicts and loads the dropdownlist.
I have an item on the page which I want to show/hide on page load based on the value of another item. If item2 is Yes, then show item1, or if item2 is No, then hide item1.
I know how to do that using dynamic action and javascript but I want to avoid using javascript. Is there a way to use APEX built-in functionality to do that? I know I can use Show action to hide an item, but I only need to show it if item2 is Yes. The APEX Show action does not have a condition
Also have the same issue with On Change event:
var result = document.getElementById("result");
var status = document.getElementById("status");
if (status.options[status.selectedIndex].text == "Completed") {
var r = confirm("Are you sure you want to set the status to Completed?");
if (r == true) {
apex.submit({request:'STATUS_CHANGE'})
}
} else {
result.value = "";
$x("P2_THE_DATE").value = "";
apex.submit({request:'STATUS_CHANGE'})
}
//set a value of a hidden field for status
apex.item("P2_STATUS").setValue(status.options[status.selectedIndex].text);
Is there a better, more efficient way to do this?
ITEM2 must get its value on load somehow, right? So, use the same code (that populates ITEM2) as a condition for ITEM1 and check whether its value is "Yes" (and display it) or "No" (so don't).
I prefer using a function that returns a Boolean to do so; something like
declare
l_item2 varcahr2(10);
begin
-- this is supposed to look like source for ITEM2
select ...
into l_item2
from ...
where ...;
return l_item2 = 'Yes';
end;
Isn't that a perfect use case to incorporate js - to have a dynamic behavior on a web page. Why would you want to avoid it? I'm just curious.
Anyway, you could however achieve similar behavior, provided the item2 is a Select List or Radio Group.
Set the 'Page Action on Selection' to Submit
Set the source used to 'Only when current values is NULL' - so the value gets stored in the session even after submitting the page.
Have the conditional display for item1 set as "ITEM is NOT NULL" and choose ITEM2 as the item.
If you follow these steps, the ITEM1 would show up after the selection of ITEM2.
I have a dropdown menu in d3.js, and I would like to get the index from the selected option. It's a list of a bit more than 50 flight companies, and right now I have this :
function choixCompagnie(){
let compagnieChoisie = d3.select(this).property('value')
}
This function activates whenever there is a change on the drop down, like so :
d3.select("#selectCompagnie")
.on("change",choixCompagnie)
The property('value') means that for instance if I click the first line of my drop down menu, which is Aer Lingus, my compagnieChoisie variable will get the value Aer Lingus instead of 0.
I need it because I then need to access some properties company by company, and my objects are in an array. So in my database I need to access the properties like this data[index].randomProperty and not like this data["Company Name"].randomProperty, since the company name is already a property.
I don't know if this makes sense, sorry if I'm using the wrong terms I'm fairly new to coding.
Thanks for the help !
edit : here is a working example http://blockbuilder.org/ArnaudStephanUNIL/a18332a561579eb929091faaff91fb6f, where the drop down gets the value but not the index
You should access your data like this:
function choixCompagnie(){
let compagnieChoisie = d3.select(this).property('value')
console.log(data.find(d => d.compagnie === compagnieChoisie).accidents);
}
I found a better, easier way to get the index from a drop down menu :
<select id="selectOptions"></select>
Once you initialized your drop down menu, you simply have to do this :
var options = ["option1","option2"];
options.forEach(function(d,i){
d3.select("#selectOptions")
.append("option")
.attr("value",i)
.text(d);
})
I have a requirement to showing all or less properties of an entity in the grid based on the page mode user select. For example I have three page modes
Minimal (will show 8 properties of an entity in the grid)
Standard (will show 12 properties of an entity in the grid)
Extended (will show 15 properties of an entity in the grid)
How can I make Select predicate dynamic to include the specified no of columns of an entity based on user page mode. Lets say I have Entity company with 15 properties I want to do something like this
dbContext.Companies.Select([predicate for choosing different no of columns?])
You cannot solve this using Predicates, because they always return bool.
What you need is a function expression that takes a Company object as a parameter and returns an object. Concretely, you need an Expression<Func<Company, object>>.
This is how you can define the three types of selection:
Expression<Func<Company, object>> minimal = e => new { e.Prop1, ..., e.Prop8 };
Expression<Func<Company, object>> standard = e => new { e.Prop1, ..., e.Prop12 };
Expression<Func<Company, object>> extended = e => new { e.Prop1, ..., e.Prop15 };
and then use them as you wish:
dbContext.Companies.Select(minimal);
// or
dbContext.Companies.Select(standard);
// or
dbContext.Companies.Select(extended);