CakePHP: Additional select box data (from associated model) appended to existing select option - forms

So far, I don't think this is possible as I've been on it for 3.5 hours now. No luck.
I have a form.
I have a select field (with select options of course) which I want to display associated data next to the select items.
For example:
On my Add Plan form, I have a select box titled Plan Details. Plan Detail (model) has a Plan Detail Note (model) (PlanDetailNote belongs to PlanDetail) which is associated. In other words, each Plan Detail has a Note about it in the plan_detail_notes table.
I want to know if it is humanly possible with cakephp to display it like so:
Select Plan Detail:
[Plan Detail Option 1] - [Plan Detail Note]
[Plan Detail Option 2] - [Plan Detail Note]
[Plan Detail Option 3] - [Plan Detail Note]
[Plan Detail Option 4] - [Plan Detail Note]
As you can see the, the note is appended to the normal select option BUT is just static for viewing only - does not need to be saved.
Is this possible with CakePHP?

just another thought, if what you actually want is
<select>
<option value="1">[Plan Detail Option 1] - [Plan Detail Note]</option>
<option value="2">[Plan Detail Option 2] - [Plan Detail Note]</option>
...
<option value="N">[Plan Detail Option N] - [Plan Detail Note]</option>
</select>
Then you could manually create the list using the getAll query (assuming the relationships are properly created)
[ in the controller ]
$plans_list = array();
$plans = $this->Plan->findAll();
foreach($plans as $row) {
$plans_list["{$row['Plan']['id']}"] = "{$row['Plan']['name']} - {$row['PlanDetail']['note']}";
}
$this->set('plans_list', $plans_list);
[ and then in the view ]
<?php echo $form->select('Plan.id', $plans_list); ?>

Haven't worked with Cake for a while, but in your Plan Details controller could you not append the Plan Detail Note before you send it off to the view?

sounds like what you want to do is display the plan detail note as text in a div next to the select box. When you select an option, you want the text in the div to be updated to the plan detail note of the selected option.
If that is what you want to happen, then that will require some ajax work. basically you will observe the field of your select box for an 'onChange' event. That event will update the innerHtml of the div with your plan detail note.
I like to store the plan detail notes as a javascript array or object, then onChange, set the div innerHtml to the value in the javascript array.

zeroSkills,
Based on your concept I was able to get it working with some adjustments. Here is what I did:
In the add.ctp (view)
...
echo $this->Form->select('plan_detail_id',$plans_list);
...
In function add() (in the plans_controller.php)
...
$plans_list = array();
$plans = $this->Plan->PlanDetail->find('all');
foreach ($plans as $row) {
$plans_list["{$row['PlanDetail']['id']}"] = "{$row['PlanDetail']['name']} - {$row['PlanDetailNote']['name']}";
}
$this->set('plans_list', $plans_list);
}
...
I did not even need to mess with my Model which was a relief!
Here is a link to an example of the option output:
http://prntscr.com/1jmid
As you can see, I appended the "Under 65" or "Over 65" based on the value of an associated table PlanDetailNote.

Related

Cypress select last option in dropdown

I have a dynamically generated dropdown with normal structure as:
<select>
<option value="10">10</option>
<option value="20">20</option>
<option value="30">30</option>
etc.
</select>
It is kind of pagination and I don't know how many items will be in the table and don't want to calculate how many options with which numbers will be in dropdown according to item count.
What I want to achieve with Cypress is simply always select the last option.
I know I can select any option by name or value, e.g. cy.get('select').select('10')
Also with index: cy.get('select').select(0)
But I don't know the last index.
I also tried select().last() but this doesn't work, as select must not be empty.
If your options are dynamic, you should ensure the list is populated before selecting
cy.get('select option')
.should('have.length.gt', 0)
cy.get('select option')
.last()
.then($lastOption => {
cy.get('select').select($lastOption.text())
})
You can do something like this. First get the number of options and then using that select the last item.
cy.get('select')
.find('option')
.its('length')
.then((len) => {
cy.get('select').select(len - 1)
})

Laravel search form using database

I have a search form with three fields: Department, Role and Location which I'm calling Contacts search and it is to be on multiple pages.
Here is a picture:
To this extent, I made it a Blade include so I could just re-use it wherever I need it.
All of the values for these fields are available to me in the Users table as I could do the following:
SELECT DISTINCT department, role, location FROM users
This would give me all of the unique roles, departments and locations.
However, for me to populate this form via the database would I have to pass the data to the parent view every time?
For instance, I was thinking something like this.
In Controller
$formFields = User::distinct()->get(['department', 'role', 'location']);
In view
#foreach(formFields as $field)
$field->department
...
...
#endforeach
The only issue is, surely I would have to send this data to every view that uses the form?
Alternatively, do I just make a SearchController that uses the User model to feed into it?
Is it possible to feed data to a partial view in this way?
Update
View composers do seem to be the way to go, however I don't feel this is valid:
view()->composer('layouts.quick-search', function($view) {
$view->with('departments', \App\User::distinct()->get(['department']),
'locations', \App\User::distinct()->get(['location']),
'roles', \App\User::distinct()->get(['role']));
});
As it doesn't seem to like multiple variables.
I also tried the following:
<select class="form-control transparant" id="department" name="department">
#foreach($departments as $department)
<option value="{{ $department }}">{{ $department }}</option>
#endforeach
</select>
But this filled the select box with:
{"department":"Digital","profile":null}
This is clearly an array, but does this mean I'll have to JSON decode this?
As I mentioned in my comment, you could do something like this:
In view
#php $formFields = \App\User::distinct()->get(['department', 'role', 'location']); #endphp
#foreach(formFields as $field)
$field->department
...
...
#endforeach
Another way to do this would be creating a group of all those views that use the partial view. Apply a middleware to that group where you assign the data to the request or share the data to the views using View::share()
View composers are perfect for this.
You create a separate view for the form, something like search and put this in a service provider:
use Illuminate\Support\Facades\View;
use App\User;
// ...
publlic function boot()
{
View::composer('search', function ($view) {
$view->with([
'formFields' => User::distinct()->get(['department', 'role', 'location']);
]);
});
}
Now every time the search view will be used, this query will be executed and the results will be passed to the view.

web2py: customizing form.vars to pass inputs id

I'm building a web app using web2py for attending employees.
this is the db in the model
db.define_table(
'employee',
Field('name'),
format = '%(name)s'
)
db.define_table(
'attendance',
Field('employee_id',db.employee),
Field('attend','boolean'),
Field('comments','text')
)
This is the controller:
employeeIDS=db(db.employee).select(db.employee.ALL)
table=[]
for eid in employeeIDS:
table.append([eid.name,INPUT(_type="checkbox",_name=eid.id,_id=eid.id),INPUT(_type="text",_name="comments",_id=eid.id)])
form=FORM( TABLE(TR("employee name","attended?","comments"),*[TR(*rows) for rows in table]),INPUT(_type="submit",_value="SUBMIT"))
if form.accepts(request,session):
response.flash="form accepted"
print(request.vars)
elif form.errors:
response.flash="form is invalid"
else:
response.flash="please fill the form"
return dict(form=form,vars=form.vars)
My question is this:
How can I access the id of the attend and comments fields in each row to associate these fields with the related employee. So, when I insert the form.vars to the attendance table, I guarantee that each employee recorded as attendance or absence and the related comments will inserted too.
Thanx
Instead of giving each comments input the same name, make the names unique, including the record ID as part of the name:
INPUT(_type="text", _name="comments_%s" % eid.id)
Then you will have form.vars.comments_1, form.vars.comments_2, etc.
As an aside, note that HTML id attributes should be unique, but you are using the value eid.id as the id attribute of both the checkbox input and the comments input.
I think a better choice is to use SQLFROM instead of FORM.
There you can customize the resulting form in the view right the layout you want to, even with HTML helper for tables, you have already used.
Please have a look at the signature of the SQLFORM - it offers a lot options as labels or showid (following the link just scroll down a little).
To exclude a field of being changed or even displayed in the SQLFORM use:
db.my_table.a_field.writable = False
db.my_table.a_field.readable = False
as described here - it's the same for SQLFORMS.

How to control Show/Hide fields at Runtime in Orbeon Form Runner?

I have created a form in orbeon form builder which has three 30 questions which are belongs to 3 categories. Now I don't want to show all the 30 questions to every one also I don't want to create different forms for each category because all these categories belongs to one module.
While adding the form I have a drop down question like "Select Category". If user select the first category then I need to display only first category related questions and hide the second and third category related questions.
Is there any way to achieve my task in Form Runner?
UPDATE:
#ebruchez, I have followed your suggestion, I tried testing this feature on default "contacts" form. I have created a new text field in the contact form named "Account Related Field" as a label and "control-10" as Control Name. Below is the screen shot for the same.
Then After that I clicked on control setting of the "Account Related Field" and under the "Formulas" tab I have added the following XPath expression in "Visibility" section. $topic='Account' following is the screenshot.
After adding the path expression I saved the contact form and published. Then I tried opening the form in form runner. But I am not able to view the "Account Related Field" field on UI after selecting the "topic" value is "Account" in the form runner. This is the screenshot of form runner after publishing form in form builder.
Did I miss something. Please help to resolve the issue. I need to view "Account Related Field" field only if "topic" field value is "Account"
Thanks in advance.
Yes you can, by using a "Visibility" formula under the section settings. For example if your dropdown is named foo and has two entries, category1 and category2, then you can write:
$foo = 'category1'
to make the section visible only if the dropdown selected category1, and:
$foo = 'category2'
to make the section visible only if the dropdown selected category2.
This doc might help.

Nested Filter options in Spotfire

I am learning to create reports using spotfire. Could you please help me to understand the feasibility.
Is it possible to change the filters based on the previous selection(filters has to be altered based on the previous section)
For Example:
I have a following table, with three columns.
Filter1 Filter2 Data
Name Name1 test1
Age Age1 test2
Location Location1 test3
I am planning to have filter options based on the column Filter1 and Filter2.
Is it possible to create a drop down with the values "Filter1" and "Filter2"?
Is it possible to modify the list of filter options, based on the first drop down selection.
For example. if "Filter1" is selected in the drop down. The list of filter options should be "Name","Age", "Location".
if "Filter2" is selected in the drop down. The list of filter options should be "Name1","Age1", "Location1".
Thank you
We can also create a cascading drop down list through the following steps.
Create a “property Control – Drop down list” myDropDownList
Select the “Unique Column Value ” to populate the drop down list (values).
Go to “Insert -> Calculated Column”
Use a simple conditional statement something like If([Value1] = ‘${myDropDownList}’, [Value 2], NULL)
Use the newly created column in the text area filter. This will be updated based on the previous section.
Thanks.
I have a solution utilizing JavaScript to effectively toggle between hidden DIVs. I'm not aware of a way to manipulate the filter object and which column it points to in the Text Area through the API. If someone does know a way I'd love to hear it!
Here is my solution with JS:
Set up your Text Area with a Drop Down for your selection as a column selector (with columns of interest chosen through the "Select Columns..." dialogue), a label displaying that selection (we will hide this, I realize it seems redundant), and 2 filters for your 2 columns.
Right click your text area and click Edit HMTL. Utilizing the HTML below, modify your HTML to match. You will want to have the 1st DIV as your drop down, the SPAN as your label which displays that drop down's property, and then the last 2 DIVS (LETTER and NUMBER in my case) as your two filters. Make sure the DIV id name matches your column name exactly.
<DIV><SpotfireControl id="8dc9d8974bde445cab4c97d38e7908d6" /></DIV>
<SPAN id=docProp style="DISPLAY: none"><SpotfireControl id="1311015997cd476384527d91cb10eb52" /></SPAN>
<DIV id=LETTER style="DISPLAY: none"><SpotfireControl id="760ae9ffd71a4f079b792fb5f70ac8b4" /></DIV>
<DIV id=NUMBER style="DISPLAY: none"><SpotfireControl id="488ef4b1289440d5be24b0dd8cfc3896" /></DIV>
Next we will implement the JS. To do so, click the +JS button in your Edit HTML. The JS itself is below. You'll want to change my inputs of LETTER and NUMBER in the first 2 getElementById references where we set them to display:none.
filter = function(){
input = $("#docProp").text().trim() //Take the text from our hidden label and trim it from any white space.
document.getElementById("LETTER").style.display = 'none'; //Reset DIV
document.getElementById("NUMBER").style.display = 'none'; //Reset DIV
document.getElementById(input).style.display = 'block'; //Set new display
}
//Run this function every 333ms or other length of time desired to update your filters.
setInterval(filter,333)
//Larger numbers mean slower response and better performance vs. faster response and worse performance. Tune as necessary.
Alternatively instead of scanning every X milliseconds (can cause some performance drag), you can make a JS button to run it manually. e.g. $("#divIdForButtonPlacement").button().bind('click',filter)
A few images of my setup for testing are shown below. Let me know if you have any questions regarding this.