Skip to main content

JavaScript Fundamentals: String Concatenation

In my CONNECTIONS2019 presentation, I showed how I use SSRS to create “Pretty Print” versions of myEvolv Treatment Plan components to use as a handout for treatment plan meetings that can be accessed by clicking a URL variable on the treatment plan itself. Several people asked me to share the method and specifically how to do the JavaScript string concatenation, which can be used in many other places.

JavaScript Strings

In JavaScript, strings are any text characters inside of a single or double quote.

var myString = "Hello world.";

You can use concatenation to “glue” strings together. In JavaScript, the concatenation operator is + , just like adding numbers together.

var string1 = "Hello world.";
var string2 = "How are you?";
var newString = string1 + string2;

The value of newString would be Hello world.How are you? Notice that There are no spaces between the sentences because I didn’t include them in the strings.

If you have added a URL variable to a form, you have already used a JavaScript string because you probably entered a default value like this:

'http://www.example.com'

This created a static URL that will always point to example.com every time the form is opened in myEvolv. Using JavaScript variables and string concatenation, you can create dynamic URLs that will be unique to a client, event, staff, or any other things you can come up with and these can be very useful for making myEvolv more user-friendly and effective.

“Pretty Print” Reports

At my agency, we find that the default printouts for things like Treatment Plans are long and difficult to read, especially for people who are not using myEvolv day-to-day. When treatment teams get together to meet about the treatment plan with the client and family members, we were printing copies of the treatment plan to share at the meeting.

Through meeting with the staff in those meetings, we determined that the main focus was to use these printouts to review the component pieces of the treatment plans, so why not come up with a way to just generate a one-page print-friendly list of Goals, Objectives and Methods from the current plan?

I was able to accomplish this using our SSRS Report Server by creating a report that would pull in all of the service_details for a specific plan and displaying them neatly.

Example of “Pretty Print” report

The SSRS Web Portal would allow staff to access the report where I could have added parameters that would allow the staff to lookup a client and select the plan they were looking to print this report for. But it would be easier if they could just click a link and have the report generate for the plan they clicked the link from automatically.

Dynamic URL to SSRS Report

Query Strings

SSRS allows you to pass report parameters through query strings. You may have seen these in web URLs that you have browsed:

http://www.example.com/search?search_term=balloon%20animals&limit=20

The first section of the URL directs you to a search endpoint

http://www.example.com/search

The ? starts the query string and then the parameters and their values are listed. In this case, the search_term is “balloon animals” and we only want it to return (limit) 20 results.

We can do the same thing with SSRS. In the case of this Pretty Print example, I only need one parameter, event_log_id. My query includes a WHERE clause

WHERE event_log.event_log_id = @event_log_id

This creates a parameter called event_log_id that the report is expecting in order to run.

The event_log_id of the Treatment Plan is on the treatment plan so we can use string concatenation to glue the report endpoint and the parameter name to a variable on the plan that holds the value of the event_log_id.

URL Variables

The URL form field type is used to create a clickable button on a form that will launch a new web browser window pointed to the URL value of the field.

You could add the field as a user-defined field and that might make sense if you are doing something like collecting a URL from someone. For example, if you wanted to get the website of an organization. In that case, you want to store the URL in the database.

In this situation, however, we don’t need to store anything in the database. We just want to generate the URL and create the button every time an event is opened, so a variable is perfect in this case. I added mine like this:

The URL field displays the URL in a ext box and then has a clickable globe icon to the right of it. I don’t like to display the url itself because they can sometimes be very long and look terrible so I put 1 in display size. That still shows the first few characters of the URL but that’s the smallest you can get it. As of this writing, the display size does not seem to effect how it looks in NX. I also make my URL variables not modifiable.

Default Value

Now for the JavaScript. We have our SSRS Web portal setup to work on the agency Network only so the url is

http://ssrs:8080/reports

The specific report I have created is located in the Pretty Print Reports directory and is called Plan Components:

http://ssrs:8080/reports/report/Pretty%20Print%20Reports/Plan%20Components

The %20 all stand for spaces

I also know that I have one parameter, event_log_id, so that is going to be a static part of the url:

http://ssrs:8080/reports/report/Pretty%20Print%20Reports/Plan%20Components?event_log_id=

And now all I have to do is concatenate the event_log_id to the end of the url and I will have my link. myEvolv stores the event_log_id of any given event in the variable keyValue, so I can just use that. So in the default value for the URL variable, I will use the following code:

var url = 'http://ssrs:8080/reports/report/Pretty%20Print%20Reports/Plan%20Components?event_log_id=';
url += keyValue;
url;

Explanation: I created a variable called url and gave it the string value of the static portion of my report URL. Then I concatenated the event_log_id of whatever event the form opens with to the end of the string using the myEvolv variable keyValue.

The url variable now holds a value like:

https://ssrs:8080/reports/report/Pretty%20Print%20Reports/Plan%20Components?event_log_id=2542C1F3-2D25-4840-97B3-A17C86652E9F

In the last line, I simply output the value of url, which becomes the default value of the URL variable.

One More Brief Example

To give an idea of a slightly more complicated string concatenation for a URL variable, another place where I use this is on our Monthly Summary events. I have created a dynamic URL variable that will launch an SSRS report where the parameters are the client’s people_id and then a date range. The SSRS Report then pulls in the specified daily notes for that client between those dates so that the summary writers can easily review the months’ activities.

Here’s the code for the default value:

var url = 'http://ssrs:8080/reports/report/Raise%20the%20Age%20Reports/Action%20Step%20Specific%20Notes?people_id=';
url += getElementFromXML(formXML,'people_id');
url += '&start_date=';
url += getElementFromXML(formXML,'udf_summary_start');
url += '&end_date=';
url += getElementFromXML(formXML,'udf_summary_end');
url;

This is pretty similar to the first example but a few difference. One, instead of using a myEvolv variable, I am just concatenating values from the form directly to the string: people_id and two user-defined date fields, udf_summary_start and udf_summary_end.

I am using getElementFromXML() to get the value from the form’s definition rather than the rendered form elements. This works well when you have default values in the form. If you do not, then those values may be null until filled in on the form.

In that case, you might want to go a different route and use similar code to the On Change field of every form element that is used in the URL with t

var url = 'http://ssrs:8080/reports/report/Raise%20the%20Age%20Reports/Action%20Step%20Specific%20Notes?people_id=';
url += getFormElement('people_id');
url += '&start_date=';
url += getFormElement('udf_summary_start');
url += '&end_date=';
url += getFormElement('udf_summary_end');
setFormElement('monthly_summary_report_url', url);

***In this example, my URL’s variable name is monthly_summary_report_url

What this does is any time the client is switched on the form or the start and end dates are changed, a new URL is generated and entered into the URL variable as the value.

In either case, you can see that I am alternating between concatenating static parts of the query string with they dynamic parts to make a more complicated query string.

How To: Create a Data Insight Report to Get Form Information

I was asked by a reader about how I figure out the form_line_id assigned to elements on a form. There are a few ways, but this is probably the easiest and it provides a tool that can be used over and over again. However, since it does require writing a custom report, I figured I would use the opportunity to walk through designing a Data Insight report using a custom virtual view.

Step 1: Writing the SQL Query

Before we get to Data Insight, we need a query to use for our virtual view. The report that I want to create is going to need to include the name of the form field (caption) so that I know I am getting the right GUID. I want to filter on the form name so that I can more quickly find the right form and form field. And if your system is anything like mine, you have multiple forms with the same or similar names, possibly even across various form families. So I am also going to want to bring in the form codes and the form family information.

All of these items are stored in just 3 tables: form_family, form_header and form_lines.

UML Diagram

The form_header table holds information about each form. Each form_line belongs to a single form_header and gets a unique form_line_id per form that it is on. In other words, even if you have actual_date on all of your forms, each actual_date element has a different form_line_id for each form it is on. Also be aware that if you remove a form element form a form and re-add it to the same form, it will be assigned a new form_line_id when it is re-added.

Forms (form_headers) belong to a single form_family and so they have a form_family_id. Similar to the above statements about form_lines, if you delete a form in the form designer and then recreate it, it will have a new form_header_id. If you import a form from development into your production system, myEvolv is going to give your form and all of the form_lines (elements) therein a new id as part of the import process. Once your production is later copied over to development, that imported form’s elements and header will have matching ids.

So here’s the SQL query we will use for this report:

SELECT
form_family.form_family_name,
form_family.form_family_code,
form_header.form_name,
form_header.form_code,
form_lines.caption,
form_lines.form_lines_id AS nx_friendly_form_lines_id,
UPPER(form_lines.form_lines_id) AS classic_friendly_form_lines_id
FROM form_family
JOIN form_header ON form_header.form_family_id = form_family.form_family_id
JOIN form_lines ON form_lines.form_header_id = form_header.form_header_id

You will notice that I selected the form_lines_id column twice and that in on one of them, I used the UPPER() SQL function. GUIDs are returned from myEvolv in lower case format like this:

494eed56-36fb-4fda-b54f-a86f1d150b38

These work fine in your JavaScript for NX, but if you are working in classic, your JavaScript requires the GUIDs to be in upper-case so the UPPER() function takes care of that for you and returns that same GUID like this:

494EED56-36FB-4FDA-B54F-A86F1D150B38

This query will provide you with both options and you can choose to use one or both on the final report.

Step 2: Create Data Insight Virtual View

Now to Data Insight to create the virtual view we will use to create the report. In order to add or manage a virtual view in Data Insight, you must be assigned to a role with “Access Configuration Area” in Data Insight. If you haven’t played with Data Insight roles at all, then this is the same as saying you must be an Admin in Data Insight. if you have the proper permissions, you will see the “Configuration” option in your Data Insight menu.

Click the “Configuration” option and then in the center column, under “Database Object Configuration”, click the hyperlink for “Create a new virtual view.”

Give your new virtual view a name and a friendly name. The name must be letters, numbers and underscores. The friendly name can have spaces.

Copy and paste your query into the Definition field and then click the “Test Definition” button. You can ignore the red underlining here since that is just Internet Explorer’s spell check at work. It does not indicate that the SQL is malformed.

If your query is valid SQL, you should see a list of the selected columns from your query appear. If not, you may have errors in your SQL to fix.

Once you have a query that passes the test, click “Save” to save that virtual view.

Step 3) Create Data Insight Report

Navigate to the Report Writing area of Data Insight by clicking the “Report Management” option in the top menu. Then click “Add” and select “Report” from the drop down menu.

Select a “Tabular Report with Header” from the Report Template options and click “OK”

When the Data Source pop-up window appears, make sure the “Data Objects in:” drop down menu has “(All)” selected. Then check the box next to your virtual view to select it and then click “OK”.

Since the data we are looking at includes 3 tiers of information– Form Families that contain Form Headers (forms) that contain Form Lines (elements), it makes sense to ad some groupings so we can see more easily what all belongs to what.

Click the “Grouping Tab”, select the “Grouped Flat-Table” radio button and then click the “Add Grouping Layer” button.

On your first layer, add the form_family_name and form_family_code field and click “OK”.

Click the “Add Grouping Layer” button again to create the next grouping. For this grouping add the form_name and form_code fields and then click “OK”. When this step is done, you should have a grouping screen that looks like this:

Go back to the “Table Columns” tab and add caption, nx_friendly_form_lines_id and classic_friendly_form_lines_id to the “Assigned Columns” list. It should look like this:

Your report preview pane at the bottom should spit out a report that includes every form line in every form in every form family in your system. It probably takes a while to load. We don’t want such an unwieldy report so we will add a filter on the form name by clicking “Modify Data Source” on the left side of the preview.

PRO TIP: Hiding the Live Preview is a good idea if you have a report that runs very slowly to avoid having to wait for the report to complete upon each change made to the report.

In the pop-up window, click to view the “Filter” tab and then click “Add a Parameter”. Select the column form_name. Change the operator value to “Contains” and check the “Ask in Report” checkbox. Make a caption for your parameter prompt and then click “OK” to close the parameter details popup and then “OK” again to close the data source details popup.

Your live preview pane should now be blank but prompting you to enter a form name (or part of one). Test your report by searching for one of your forms.

You should see something like this in the results:

The first result in my report searching for “Compass” is for form lines on the Compass Address Information form in the Address Info for People form family. If I look at the form in form designer, I will see all of the same elements listed. Keep in mind the groups are also form elements and therefore are include on the form_lines_id. That is what “Address Information” is on the Compass Address Information form.

At this point, you can make the report look and work to your liking by changing the column captions, adding sorting, removing pagination, etc. Be sure to save your report and move or copy it from your personal reports folder to the Shared Reports if you want to allow others to use the report too.

myEvolv Tips: Reusable User-Defined Picklist Fields

When you are building forms and have to create new database fields, best practice is to give the columns generic names so that you can use them again on other forms in the same form family. For example, if you need to link a tenth diagnosis (yes, the event_log has 9 diagnosis columns!) on a People Activities form, you should name it something like udf_diagnosis10_id rather than for the specific form like udf_extradiagnosisforclinicprogressnote. This will allow you to keep your database neat and help prevent running out of columns in your _x tables.

You may have run into a situation where you setup a user defined foreign key field on one form and had it working beautifully. However, when you went and tried to re-use it on a second form, you found that you could not select any look-up tables to use with it. What happened there?

You missed a crucial step in creating a user-defined database field. Here’s how to avoid making that same mistake going forward.

When you got to create a user defined foreign key field, use the [Data] Foreign Key Column attribute. Like the column name and data type, this attribute is only available when you first create the new column. If you forget this step, you cannot go back, and it is the reason that you cannot link a look-up table on subsequent uses of this column on other forms.

What to choose?

This depends on what picklist(s) you want to use with this column.

For example, if we go with the initial scenario, the picklist I want to use will consist of diagnoses so the foreign key column I want to select is diagnosis_id. This will allow me to reuse the column on additional forms as long as I use a picklist that is diagnosis-based.

User defined fields are commonly paired with a user defined look-up table. In order to re-use these, you should select the user_defined_lut_id foreign key column. Since all of your user defined look up tables use the user_defined_lut table, they all use the same column as their primary key.

If you need help figuring out which column to select, first select the look-up table you intend to use. In the picklist for look up tables, there is a column called “Table From”. Many of these will be views, but you should be able to figure out what the underlying table is in most cases. In our example, I want to use a look-up table from the diagnoses_view and so I know that the diagnosis table and therefore the diagnosis_id column is what I should select.

myEvolv Tips: Subform Field Manipulation

Credit for figuring these out/discovering them goes to Perry. I find myself referring to them in a training binder I got from last year’s NY Training Summit and figured it would be easier to just get them up on the web so I don’t have to go hunting for that binder every time. The following code works for Classic.

Subform Considerations

Subforms have to be handled differently than forms when it comes to JavaScript because while in the form designer, the two things look identical, the way that myEvolv renders a subform in the browser is very different from how it renders a form. But it isn’t radically different and the main changes account for the fact that a subform can have one or more rows and so you need to be more specific about which field you are trying to manipulate so that you don’t change every line simultaneously.

Scenario 1: Get the Value of a Subform Field

This code is for use within the subform, e.g. if you want to default the value of one field based on the value of another on the same subform.

self.getElementFromXML(currentRowXML, 'column_name');

Note the self object is being used here. This is the subform object as distinguished from the parent form object. The parameter currentRowXML then further narrows it down to the current record/row on the subform that you are concerned with.

Scenario 2: Set the Value of a Subform Field

Again, for use within a subform, this code can be used to set the value of a field in the same subform, e.g. when you want the On Change event to auto-populate a field.

this.form.'column_name'.value;

If you are checking a checkbox, use this code:

this.form.'column_name'.checked = true;

Note that in this code, you do keep the single quotes in the code for it to work properly. All you change is the column_name

Scenario 3: Get the Value of a Parent Form Field

With this code, you can get the value of a field in the parent form based on an action in the subform.

window.parent.getFormElement('column_name');

Note the window.parent is the only difference from the code you would use on the parent form. This is what allows your code to ‘jump up out of the subform’.

Scenario 4: Set the Value of a Parent Form Field

Maybe you figured it out by now but you can use the same small change to set values on the parent form from the subform.

window.parent.setFormElement('column_name', value);

Scenario 5: Trigger an Alert from the Subform

Alerts are useful in guiding user activity and you can trigger them from subforms. Similar to the last two, the trick is moving back up the DOM to the parent form to trigger it.

window.parent.window.alert('Alert Message');

Other Possibilities

It is possible to go the other way and get and set values on subform records from the parent form, however, it becomes a much more complex problem that requires very specific solutions for very specific challenges. That is because of the One-to-Many relationship that the subforms have with the parent form. For these types of situations, you will probably be targeting the subform itself and then looping through each record to get or set values.

How To: Create a Better Treatment Link Subform

One of the most powerful aspects of an electronic health record is the ability to link service documentation to a client’s goals and objectives and to ensure that the services provided are related to the clients current goals and objectives.

myEvolv provides a simple toggle setting to add a Treatment Plan Link on service documentation in the event setup.

This setting adds a system subform to the bottom of your service documentation forms that includes a Treatment Link column for selecting a goal from the client’s treatment plan, an Additional Treatment Detail column for selecting a child objective or method from that goal and a Notation column for capturing a note.

After attempting to use the system subform for several months, we noticed a couple of things about it that we didn’t like. The main issue is that the subform does not filter to list only goals from the most recent approved plan. It lists all of the goals that ever existed for the client. In our programs, plans must be reviewed as often as monthly so the list begins to grow very quickly and we were finding that users were often linking old goals to their current documentation. Also, you are stuck with the subform being way at the bottom of your form, which isn’t always ideal.

I used the following method to create a better subform for our direct care workers to link their service documentation to treatment goals without having to sort through a huge list of goals and ensure they always picked goals that were currently in place.

Step One: Get the service_plan_header_id of the most recent completed treatment plan onto the service documentation form.

For this task, we can use a variable since we only need to filter at the point where the service documentation is being added. If someone opens last year’s event and the variable (which will not be visible anyway) has the current treatment plan’s service_plan_header_id in it, that doesn’t affect anything other than the subform’s Goal picklist, which will be locked since the event is complete.

I added a Custom String variable to my form with the name current_plan

In order to get the service_plan_header_id of this client’s most recent treatment plan, I used the following JavaScript code for the Default value property:

var conditions = 'program_providing_service=\'\''+programPS+'\'\' AND actual_date = (SELECT MAX(actual_date) AS most_recent FROM service_plan_event_view WHERE people_id = \'\''+parentValue+'\'\' AND program_providing_service=\'\''+programPS+'\'\' AND approved_date IS NOT NULL)';
var plan_id = getDataValue('service_plan_event_view','people_id', parentValue, 'service_plan_header_id', conditions);
if (plan_id == null) {{
plan_id = 'NONE ON FILE'
}}
plan_id;

The first line of this code is setting up the SQL conditions that will be passed along in a WHERE clause query executed by the getDataValue() function. In my case, I wanted to be sure I got the most recent service plan event that matches the client for whom this service documentation is to be entered and matches the program providing service of the service documentation. The latter is necessary in case the client has more than one treatment plan at a time in different programs. The approved_date IS NOT NULL clause ensures that if there is a treatment planner working on a draft, the draft goals do not list for the direct support staff doing service documentation.

In the second line, we use this condition statement as the fifth argument in the getDataValue call. Here we are looking for a treatment plan in the service_plan_event_view that has the matching values from above and returns the service_plan_header_id

Then I checked to make sure a service_plan_header_id is returned. If one is not returned, I set the variable plan_id to be ‘NONE ON FILE’ mostly as a way to make sure my code was executing. This will be the value that fills in if someone goes to add service documentation for someone who has no plans on file for that program providing service.

Finally, I echo the value of plan_id so that the value will populate the form field.

Step 2: Create a subform similar to the system version to add to your service documentation form.

For my purposes, the subform didn’t need to be much different than the system subform. We wanted the direct support staff to select the Goal and Objective that was worked on and then enter a note related to the specifics of the objective selected.

I copied the default form in the Treatment Plan 2 Event Link – People B2E form family and made modifications.

This is what the overall form looked like in Form Designer when I was done:

Event Log Id and Additional Treatment Detail were from the original form. I left them on but pushed them to the top and made them not visible. Notation is also the same field as from the original form but we decided to make it required.

Goal is the Treatment Link from the old form. I changed it to use the Treatment Plan Goals by Plan Look-up Table so that I could use the service_plan_header_id as a parameter.

For the Depends On Other property, I used the code

getParentFormElement('current_plan')

This gets the value of the variable we created in step one and uses it as that @param2 shown in the Look-up Table Picklist’s Condition column. This is the piece that will filter the Goals picklist on the subform to only list the Goals from the treatment plan with the service_plan_header_id we supply it.

Finally, I created a new database field to use for our Objective field. I set it up as a Foreign Key type of field and I used the Service Plan Details (child nodes) Look-up Table.

This look-up table uses the service_plan_details_id to filter for a list of objectives that belong to that service_plan_detail . In this case, we are selecting a service plan detail in the Goal field, so we can filter this LUT to only show the Objectives that belong to that goal. To do that, I just select the Goal field as the Depends On property.

***Note: You can go one level deeper and add a picklist field to the subform for the methods by repeating the steps for making the Objective field except selecting the Objective field for Depends On since Methods belong to Objectives the same way that Objectives belong to Goals.***

Once you have your subform ready (remember to check the box for Is Visible on Subform!), add it to your service documentation form. Assuming your variable from step one is pulling correct service_plan_header_id’s, you should see only the most recent active goals in your Goal field and then only the objectives for that goal in your Objective field.

How To: Create an Events to Complete Subreport

EDIT 3/16/2018: Reader Jen G. pointed out that a staff member’s staff_id != people_id in all cases and therefore my approach would not always work for all staff. She proposed a different form to copy for this setup that will work 100% of the time so I have updated the post to reflect her proposed changes and fix my approach. Thank you, Jen!

This comes from a reader request. The goal was to create a subreport in the Agency > Staff & Security > Staff Information formset that would list the service events that a selected staff member had not fully completed. The subreport could be useful for supervisors to follow up on events that their supervisees needed to e-sign or otherwise complete, especially in the event where a staff member was transitioning out of the agency. The following is my proposed solution to that problem:

Step One: Create a User Sub Report

Navigate to Setup > User Tools > Sub Reports – User > User Sub Reports and create a new User Sub Report. Give the sub report whatever name and code you wish. For System Sub Report, select any report that has event_view as a Data Source Name. In my case, I chose the “Compass (Initial) Peer Delivered Services” report.

When you are selecting from this list, the only critical thing is the data source name. Everything else only speaks to how that particular report had been configured with the data source for that particular system report. It will tell you which columns were used to join and the remarks column will give you and idea of how it might be used “out of the box” but you can change all of those properties once you have the data source linked to your user sub report.

On your new sub report, change the following properties:

SQL Code: is_service_event = 1 AND is_locked = 0

This will filter the event log to only show events that are service event and only those that are not locked. The event_view has many columns in it that will allow you to customize this filtering to get exactly what you want to see. Some other options are: completed, is_amended, is_billed, is_deleted, is_e_signed, is_final

Report Fields: Pick any that you want to display. For my subreport, I wanted to show the client (full_name), the event (event_name), and the date of the event (actual_date).

The one that you need to have for sure is staff_id, which we will mark as a join column. In the Overwrite Form Field to Join, put some value (I used “staff”) and for the operator, choose “Equal”. Remember the Form Field to Join that you used for later. Below is a screenshot of my setup:

Step Two: Create Form

You don’t have to create a whole new form to house this subreport. You might choose to add the subreport to one of the already existing forms in the Staff Information formset. The important thing for this step is that the form you end up putting this subreport on MUST have the staff’s people_id staff_id on it. Maybe the form already has it on there or maybe you need to add it in the form of a variable. I will show you how to add it if it doesn’t already exist.

In my case, I am adding the subform to a custom version of the Personal Info formset member. So in form designer, under the Personal Information form family, I copied the Staff Personal Information Form. On my custom form, I hid all of the fields that I did not want users to see and I added the subreport that I created in part one. Now I need to make sure there is a staff_id named “staff” for the subreport to join on.

To do this, add a regular string variable to the form. Caption it whatever you want but give the variable name the same name as your used for your Overwrite Form Field to Join on the subreport created above. We need this variable to default in with the staff member you select’s staff_id so in the default value field, we will put the following code:

keyValue

Edit: Because I used a form from the Personal Information form family, the keyValue in this case will be a people_id and not a staff_id. Therefore it will only work right on those staff who have the same value for their staff_id as they do for their people_id and this is not always the case. If you copy a form from the Staff form family, you can simply use keyValue because it is the staff_id. But if you are copying a Personal Information form, use the following code to get the staff_id:

getDataValue('staff', 'people_id', keyValue, 'staff_id');

Here is a screenshot of my variable’s configuration:

Once you have confirmed that this field is pulling in a GUID, you can make this field invisible on the form.

Step Three: Create a New Formset Member

With your new form created, you can now associate it with a new formset member so that you can display it for users.

Navigate to Setup > User Tools > Formset Maintenance > FormSet Members and select the Staff Information Formset from the Agency module.

Create a new formset member, name it what you’d like and then select the Personal Information form Family and your new form as the Default Form. Make sure Is Active is checked and then save. Remember to go through the Navigation scheme setup and turn on the new formset for the users who will need access.

The Final Product

With everything setup above, you can navigate to your new formset member and select a staff member. Your form variable should get a default value of the staff you selected’s staff_id and your sub report should be joining on the that staff_id, thereby filtering the event_view to that staff member’s events. Your SQL Code statement on the user sub report will further filter the event_view to just those you are interested in seeing. In our case, the service events that are not locked.

Troubleshooting: Event Not Always Honoring Edit Form

I had this issue come up for me recently while working on making placement disruptions more secure. By the nature of placement disruptions, we needed to allow users to go back in and edit the placement disruption to add an end date but we did not want other fields to be editable at that point so I copied the placement disruption forms, made the fields we wanted to lock down not-modifiable and then linked the new forms to the event as the form to use on Edit.

While testing, we noticed that if we saved a new placement disruption and then immediately edited it, the Add form was being used. If we refreshed the list of placement disruptions and then edited the placement disruption, the Edit form was being used as intended. Based on how placement disruptions actually get used, this probably would not be a problem because typically staff will set them up one day and edit them another day, which means that they will have gone through at least one refresh. Still, I was annoyed about this and wanted to figure out how to make it behave. While I used this fix specifically to get the Edit form to be used, you could apply this in any situation where you need the event information to update in the list so that other form functionality works properly as well.

The Problem

I noticed that after saving the placement disruption, the list of placement disruptions did not refresh itself. The most recent placement disruption should be showing at the top of the list but it was being appended at the bottom of the list and the list never refreshed itself to fix the order like it typically does. Also the placement disruption type did not fill in on the list indicating that the list refresh was necessary to update the event information enough to indicate that the edit form should be used on edit instead of the add. A manual refresh made all this happen. So the problem was related to the event listing not refreshing after save.

This is the list of placement disruptions before adding one.

After I added a placement disruption, the list did not refresh. The new placement disruption is at the bottom.

After clicking the Refresh button, the list updated to fill in missing information and list in the proper order.

The Solution

I went through the formfunctions.js file looking for any code snippet that would refresh the listing after save and found one. If you have any forms that do no automatically refresh the event listing after save, you can add the following code to the After Save Code property of the form:

self.refreshCallerWindow = true;

With this code on the form, after I save the form, the list of event automatically refreshed itself rather than requiring me to click the Refresh button. When I click to edit the newly created placement disruption, the Edit form opened.

With the code on the form, after saving, the list displayed with the proper information filled in and in correct order.

How To: Enforce ZIP+4 in Client Demographics

Some payors are beginning to require that client addresses utilize the ZIP+4 ZIP code in order to get paid.  The ZIP code field in myEvolv has a datatype of Zip Code which appears to be a string field that allows up to 10 characters.  This means that you can store a 5-digit ZIP code or a ZIP+4 in the field.  Furthermore, the functionality for auto-filling the city and state fields based on the ZIP code will work with either type of ZIP code.

One thing that is lacking is the ability to force users to input a ZIP+4 in the ZIP code field.  The following guide will show how you can add some form validation to the Client Demographics form that will help to prevent users from entering only the 5-digit ZIP code.  While we will be looking at only one set of forms, you should be able to apply the same changes to other forms and address subforms to achieve the desired result elsewhere in the system that addresses are collected or edited.

Setup New Demographics Formset Member

For the purposes of this demo, we are going to modify the Client Demographics form.

This is a system form and we cannot directly make changes to it so instead, we must create a custom demographics form, address subform and formset member so that we can make the changes we want.

Copy the ‘Address by ZIP code‘ Form

This form is in the Address Info for People form family. This is the form that is used for the Personal Address subform on the Client Demographics.

Copy the ‘Client Personal Information‘ Form

This form is in the Personal Information form family and is listed at the top as the default form. This is the main form that loads when you go to the Client Demographics formset.

On your newly-copied, custom version of this form, swap your custom Address by ZIP code subform in for the default Address by ZIP code subform.

Remember that when you copy and begin editing these system forms, a good rule of thumb is to only add to the form or carefully edit what is on the form so that you do not have downstream effects. Avoid deleting elements. If you don’t want them to be visible, simply hide them.

Create New Formset Member

Select the Client Personal Information FormSet in Formset Maintenance. By Default, the Client Demographics formset member is ordered #1. Add a new formset member and copy the settings for it just like the system default Demographics formset member EXCEPT that we will be using our custom Client Personal Information form instead of the system form in the Default Form field.

With the new formset created, remember to make it available to all navigation schemes which need the ZIP+4 validation. In order to avoid confusion, you can make the default formset member unavailable to those with the new formset.

Pro Tip: I temporarily put “TEST” in the Tab Caption of my custom formset so that I could find it easily when adding it to the navigation schemes.

You now have a separate and customizable Client Demographics formset to play with in your system

Modify Forms to Validate for ZIP+4

We will need to make changes to both of our forms in order to cover all of our bases. Our method for validating is to check the subform zipcode field when it is changed and determine if the zipcode entered is comprised of 10 characters. If the zip code is other than 10 characters, we will alert the user that they must enter a ZIP+4. If they ignore the warning and attempt to save anyway, we will prevent the save and alert them again that a ZIP+4 must be entered.

Custom ‘Client Personal Information’ Form

Step 1) Add a variable to the form just above the Personal Address subform. This variable will be used to store our ZIP code validation state that we will check before saving.
I named my variable is_zip_invalid and gave it a Regular Numeric datatype. You can set your variable to be not visible.

Step 2) Add the following code to the form’s “Before Save Code” property:

if(getFormElement('is_zip_invalid') == '1'){{
alert('You must use ZIP+4');
formValid = false;
}}

The code above checks to see if the value of the variable we just created is ‘1’. If it is, then it gives an alert and tells myEvolv to abort the save because this form is not valid. On the subform, we will add code that will set the value this variable based on what is entered in the zip code fields.

Custom ‘Address by ZIP Code’ Form

Step 1) Add the following code to the ZIP Code field’s “On Change” property:
This code can go under the setAddressFromZip(this); line.

var zip = self.getElementFromXML(currentRowXML, 'zip_code');
if(zip.length != 10){{
window.parent.window.alert('You must use a ZIP+4');
window.parent.setFormElement('is_zip_invalid', 1);
}} else {{
window.parent.setFormElement('is_zip_invalid', 0);
}}

The code above creates a variable named zip and assigns it the value that user enters into the ZIP Code field. The script then checks to see if the value is 10 characters long. If it is not, the code produces an alert to remind the user that a ZIP+4 is required and then sets the value of is_zip_invalid on the parent form to 1. If the value is 10 characters long, the script sets the value of is_zip_invalid on the parent form to 0.

Step 2) Add the following code to the form’s “Before Save Code” property:
Since it is possible for users to open the subform in a new window, we also need to do some validation on the subform itself in case a user ends up adding or editing addresses via this method/

var zip = getFormElement('zip_code');
if(zip.length != 10){{
alert('You must enter a ZIP+4 in order to save');
formValid = false;
}}

The above code does the the same thing that the “Before Save Code” from the other form does. The only difference here is that we have direct access to the value entered in the ZIP code field so we use that to validate the form rather than the variable flag.

When put altogether, you will have a custom Client Demographics formset that will warn users at the time of changing a ZIP code field if they are not entering a ZIP+4 and will not allow saving until the ZIP code is fixed.

One Vulnerability

The way that this is setup, the value of our variable is_zip_invalid is changed any time a zip code is updated so if the last zip code altered is valid, all zip codes will be accepted as valid. So for example, let’s say that I edit two zip codes on the form. On the first one, I only put in the 5-digit ZIP code. I get an alert telling me to use the ZIP+4 and my variable gets assigned a value of ‘1’. Next, I close the alert and alter the second ZIP code and this time I enter the ZIP+4. Our code executes to check that the ZIP code I entered here is valid. It sees that it is and assigns our variable a value of ‘0’. The form will successfully save even though I still have a 5-digit zip in the first address that I edited.

More complicated code might be able to do a more thorough job of validating multiple zip codes before save but I haven’t figured that out yet.

How To: Default a Date Field Value Based on Another Date Field

NOTE: THIS POST IS AN UPDATED VERSION OF THIS POST

When working on treatment plans in myEvolv, you will notice that many of the treatment plan component forms contain both a start date and a target completion date.  One of the programs I was building a treatment plan for wanted to have the target completion date on the form but always wanted it to be 90 days from the start date.  Instead of making each clinician calculate 90 days from the start date and fill it in themselves, I used this method to take the date value from the start date and update the target completion date field with a value that is 90 days later.  I will walk you through the JavaScript that I used so that you can make adjustments based on your needs.  The full snippet of JavaScript will be at the end.

two-fields

Where does the code go?

The first consideration is where to put the JavaScript.  In this case, used the ‘On Change Script’ field property on the field that will be modified by the clinician, ‘start_date’.  myEvolv provides us with access to 3 events that we can use to trigger our JavaScript handlers (the code we want to execute):  ‘On Change’, ‘On Click’ and ‘On Load’.  The ‘On Change’ event is fired when the value of the field has been changed.  This is the most suitable event to use in this situation since I do not want the new date value to calculate until there is a value in the first date field.  Furthermore, if a clinician makes a mistake entering the start date, I want the new date to recalculate when the clinician makes an adjustment.  Both of these scenarios are covered when using the ‘On Change’ event.

Get the ‘start_date’

The first line of JavaScript code’s purpose is to get the value that has been placed into the ‘start_date’ field and convert it into a proper JavaScript Date object so that we can manipulate the date easily. I declared a variable named date and set it to be a new Date object passing the value of the ‘start_date’ field as its argument:

var date = new Date(getFormElement('start_date'));

Calculate the ‘target_date’

Now with the date entered by the clinician converted to a Date object, I can perform some calculations on the date using the ‘getter’ and ‘setter’ methods built in to JavaScript Date objects. In my scenario, I need the ‘target_date’ field to be +90 days from the ‘start_date’ so I used the getDate() and setDate() methods:

date.setDate(date.getDate() + 90);

If I wanted to do +3 months instead, I would use the getMonth() and setMonth() methods:

date.setMonth(date.getMonth() + 3);

If I wanted to do +1 year, I would use the getFullYear() and setFullYear() methods:

date.setFullYear(date.getFullYear() + 1);

There are also methods for getting and setting hours, minutes, seconds, and milliseconds, but I am dealing with Date Only fields in this scenario.

Format the ‘target_date’

Now that the date object has my new date stored in it, I need to put that value into the ‘target_date’ field. However, the date in the date object is not formatted in a way that myEvolv’s date fields like so I need to pull the individual date elements from the object and build a string value to place in the date field. I accomplish this first by declaring variables for the month, day and year:

var mm = date.getMonth() + 1;//+1 is needed because in JavaScript Date objects, January is 0
var dd = date.getDate();
var yyyy = date.getFullYear();

Now I declare a new variable called formatted_date and set its value to a concatenated myEvolv-friendly string:

var formatted_date = mm + '/' + dd + '/' + yyyy;

Set the ‘target_date’

setFormElement(‘target_date’, formatted_date);

 

One Caveat

You may be inclined to disable the ‘target_date’ form field so that clinicians cannot change the value after it has been calculated. I was unable to get that to work, however. When a form field is disabled, it is excluded from being saved so for now it would seem that you have to keep the form field modifiable. If you used this same similar* code in the ‘On Change Script’ property for ‘target_date’, you could prevent the ‘target_date’ from being changed by effectively reverting any attempts at changing the ‘target_date’ manually.

*You will need to also add some JavaScript to validate that the ‘target_date’ has been changed because if you just put this exact same code in the ‘On Change Script’ property for ‘target_date’, you will end up in an infinite loop when ‘actual_date’ is changed on the form and you will crash the browser.

The Full Code

var date = new Date(getFormElement('start_date'));
date.setDate(date.getDate() + 90);
var mm = date.getMonth() + 1;
var dd = date.getDate();
var yyyy = date.getFullYear();
var formatted_date = mm + '/' + dd + '/' +yyyy;
setFormElement('target_date', formatted_date);

We are using cookies on our website

Please confirm, if you accept our tracking cookies. You can also decline the tracking, so you can continue to visit our website without any data sent to third party services.