Thursday, October 15, 2009

Change the Advanced Search Page Default Search Operator

In my OOW presentation yesterday I showed that it is possible to change the default search operator for a specific advanced search page. The JavaScript required to implement this behavior follows:

<script type="text/javascript">
$(document).ready(function() {
var newValue = 9;
var coll = $("select[name='APT_UI_SCRIPTS_MENUNAME$op']");
if(coll.val() != newValue) {
coll.val(newValue).change();
}
});
</script>

Note: The code above uses jQuery for event handling and therefore requires that you inject jQuery along with the JavaScript above. I demonstrate how to accomplish this in the injection blog post referenced below.

In my PeopleTools book I provide full details for implementing this behavior, but if you want to get a head start, I'll give you some hints. First, you need a mechanism for injecting this JavaScript into a search page. To learn more about injection, read my post Injecting JavaScript Libraries into PeopleSoft Pages. Next, you need a way to target a specific component. For this, see my post JavaScript complement of PeopleCode Global Vars. Your final step is to write some JavaScript to determine if the open page is a search page. I determine this by testing for the existence of an object named #ICSearch.

To determine the numerical code for a search page operator (9 = between), open the HTML source of any advanced search page and search for the option child nodes of PSDROPDOWNLIST.

Update (April 15, 2010)

The code above works great with PeopleTools 8.49 and lower. PeopleTools 8.50 uses Ajax to switch from the basic to the advanced search page. The 8.50 Ajax does not trigger the $(document).ready code. I have another solution for PeopleTools 8.50 (documented in my book). I'll post it soon.

25 comments:

Kim said...

Hi Jim, I need to capture the search params entered on a page for all the components that the user traverses, then put all the links visited on a seperate pagelet, so that he can go directly to that page clicking the urls captured - basically hot links. your Idea how to go aboubt this?

Jim Marion said...

@Kim, have you seen the PeopleTools 8.50 Most Recently Used items in the Favorites menu (MRU)? I believe it does exactly what you are referring to. To implement this yourself, I would create a record definition for storing URL's, an IScript for inserting URL's, and then add some JavaScript to PT_COPYURL (see Injecting JavaScript Libraries into PeopleSoft) to send the strCurrUrl variable up to your IScript (I reference strCurrUrl in comments to several of my posts. You can find them from this Google search). strCurrUrl contains the level 0 search keys so you can open a transaction directly. Unfortunately, this IScript/JavaScript combo would run every time the page loads (FieldChange, etc), I don't have a good way to avoid this. One way to handle this is to key the table by OPRID and URL. If the row exists, you ignore it, or even better, increment a ranking number. The additional posts will add overhead, but you might be able to ignore it. Since you are using an IScript to handle the URL post, it is much lighter on the app server than serializing the component buffer.

Kim said...

Many thanks for that Jim, let me try it!!! And I dint have a chance to look at the featurei in 8.5. But, yes that is exactly what I am trying to do.

Cory Uhrich said...

Has anyone gotten this to work other than Jim? I need to do this but haven't figured out how to call the javascript on a search page. Any help would be greatly appreciated. Looking forward to the book Jim, I have already pre-ordered it.

Cory said...

Ok, I figured out how to get it on a search page from your other post. Now I get "object expected" on I.E.

Here is my code...
$(document).ready(function() {
var newValue = 2;
var coll = $("select[name='C_PERS_SRCH_REH_NATIONAL_ID$op']");
if(coll.val() != newValue) {
coll.val(newValue).change();
}
});

Jim Marion said...

Did you inject jQuery per my instructions at the bottom of the post? It sounds like IE doesn't like "$"

Jim Marion said...

@Cory, one more thing... If you inject jQuery using the technique I show, then you will also have to inject the script on this post. You won't be able to place this script inline. The problem is that when you inject jQuery, your browser will asynchronously download jQuery, but will continue to process the existing script. The end result is that the script (which requires jQuery), will process before jQuery is loaded and will give you the "Object expected" error. Firefox with the Firebug console might give you more help, but I think it will say something like, "$ is not defined."

Cory said...

I did not, is there a way to do it without using jQuery?
Thanks

Jim Marion said...

@Cory, yes there is. I am a huge jQuery fan because it dramatically simplifies my code. If you prefer to do it without jQuery, then you want the stuff inside $(document).ready to run on document.onload. Search the internet for attachEvent. I believe that is what you want to use so that you don't overwrite any PeopleSoft delivered onload code. Next, replace $("select[name='APT_UI_SCRIPTS_MENUNAME$op']") with document.getElementById("THE_ID_OF_YOUR_FIELD$op") and adjust the selected item accordingly. It has been a really long time since I've done this without jQuery, so I'm no help there. Next you want to trigger the onchange event. Be sure to keep the if test. You don't want to trigger the onchange event if the value is already set to your new value.

If you aren't using jQuery, you can ignore the whole injection thing and just put your code directly in an HTML definition like PT_COPYURL. Also, be sure to test the result of document.getElementById. If it didn't find that element, then don't run the code. jQuery does this automatically, but without jQuery, you are on your own. If the element doesn't exist, then you might be on the basic search page and you want your browser to ignore the code.

Cory said...

Is it possible to use Google's hosted jQuery?

Example...
http://dl.dropbox.com/u/224797/JavaScript.txt

It says I have syntax errors on "var newValue = 2;"

I also tried without calling jQuery but its returning null for "coll" which I think it means that its executing the JavaScript before the page loads. I couldn't seem to figure out the attachEvent piece. I am just placing it on PT_COPYURL. Any ideas? Thanks again for the replies.

Jim Marion said...

@Cory, A couple of issues:

1. PT_COPYURL is JavaScript, not HTML. This means you can't put <script> tags in it. To include additional JavaScript, you have to inject as described in my post on JavaScript injection.

2. If you inject a JavaScript library and want to execute JavaScript that depends on that injected JavaScript, you have to inject it as well. Otherwise, the remaining JavaScript will execute before the library is loaded.

If you do not have access to your web server, you can place both of these (your JavaScript and jQuery) in message catalog definitions and serve them from an IScript.

Yes, you can use the hosted jQuery instead of hosting your own copy. I don't like this solution because it gives someone else direct access to your page content.

Cory said...
This comment has been removed by the author.
Cory said...
This comment has been removed by the author.
Cory said...

Ok, I now have jQuery on the server and I injected the library, but now am trying to inject the above script without success. Do you have an example on how to inject the above code? Thanks again!

Jim Marion said...

@Cory, it sounds like you are getting this figured out. I am sorry you have to struggle through it. My book devotes a few hundred pages to these topics :)

Yes, document.write is how you inject code while the page is loading. Yes, the example is half way down the post Injecting JavaScript Libraries into PeopleSoft Pages. To inject the code on this page, place the code in a static *.js file on your web server, just like your jQuery file and then add this line immediately following your jQuery injection line:

document.write("<scr" + "ipt id='xxx_ui_search_op' " + "src='/scripts/name_of_searchop.js'><\/script>");

When you save the JavaScript, just remove the <script> HTML tag wrapper. Since it is a .js file, you can't include HTML tags.

If you are unsure as to whether your injection is working, Try using Firefox and Firebug, Chrome, or Safari. These three browsers show resource downloads and have a JavaScript console that allows you to type things like $ and see results. Fiddler is also a very good tool for inspecting downloads. So, to see if injection is working, the first thing you need to do is see if your browser is downloading jQuery and your additional search page script. Fiddler, Firebug, Chrome, and Safari will show this. If injection is working, you will see an http request for the file.

Next is to test if your browser is interpreting the injected JavaScript. To test this, change your URL from .../psp/... to .../psc/... and then type $ or window.jQuery into the JavaScript console. This will tell you if jQuery is working.

Once that is working, navigate to your advanced search page and copy/paste the part inside the $(document).ready into the JavaScript console.

Oh, one more thing. Are you using PeopleTools 8.50? This code doesn't work on 8.50. My book has code for 8.50, but I haven't posted it on my blog yet. I'm working on a post for that. Hopefully that is not the case for you.

Cory said...

That did it! Awesome. (We are on 8.49) Fiddler showed 404 errors on my custom *.js files, so I found that if I put in the environment name in the path it worked.
/HRDV/scripts/jquery-1.4.2.min.js

Problem is I don't want to have to hard code environment names in the path for each webserver in my js files. Any ideas on how to get around that?

Next step now is to make it specific to the component and page.

Thanks again for your patience and help with this.

Jim Marion said...

@Cory, from your post, it looks like you are still using a relative URL (no server name), but you had to put in the env name (HRDV). Is this because you are using a reverse proxy or because you are placing these files in a sub directory of ../applications/peoplesoft/PORTAL/?

To work around the URL issue, I use regular expressions to parse strCurrUrl or window.location.pathname... actually, that is what I'm doing here, but for different pieces of the URL.

Cory said...

Yes, we are placing them in a sub directory of applications/peoplesoft/PORTAL.

Can I just use the existing .js and put in the regular expressions in there?
Thanks

Jim Marion said...

Yes, place it in the existing js.

Cory said...

That did it. I parsed it out, used the envt name, and then only had it execute on the specific page for that field. I really appreciate your help. Cant wait for the book!

Jim Marion said...

@Cory, cool. Thank you for the update.

Dan Kibler said...

Jim

Do you have any experience using the jQuery validate plugin to do client-side validation in PeopleSoft? I've played with it a bit with no success. I can get the validation to run but it does not seem to catch my errors.

Cheers
Dan

Jim Marion said...

@Dan, unfortunately, I have not worked with it.

Pressure said...

This question is not regarding this but I have a small question. Is it possible to change lookup prompt image on a particular field(from glass image to my own custom image) . And also in grids/scrolls for next/previous and add and delete we can change the image but generally leave it to *use default image* , just want to know where do I change this default image so that its effective everywhere in the system. thanks in advance.

Jim Marion said...

@Pressure, using the inspector tool in Firebug, you can hover over the magnifying glass to see the src attribute. From there you will see that the image name is PT_PROMPT_LOOKUP_dddd.gif. The _dddd suffix is a number to "trick" browser caching. Based on the name (and the fact that tools stores most images in app designer image definitions), you can assume that the PT_PROMPT_LOOKUP image is an image definition in app designer. You can prove it by looking for the image in app designer. I did this and found that image in app designer. Now that you know this, you can change the image on a global basis by updating the image definition in app designer. After making this change, I suggest you clear your web server cache and restart your web server.