Scripting on propertyChange

So maybe I am misunderstanding how this works but I have a on propertyChange script on a Vision Template that runs each time a UserChoice template parameter changes (which is later bound to a dropdown list in an overview screen). On this template I have a Internal Property that is a dataset which is a single column and possibly many rows that pulls data from a Named Query based on the user selected. The on propertyChange script is supposed to change the background color of the template based on the results of the dataset and the UserChoice parameter.
My propertyChange script looks like this:

propertyName = event.source.UserChoice
for row in range(event.source.IncompleteJobs.getRowCount()):
	for col in range(event.source.IncompleteJobs.getColumnCount()):
		event.source.background = (255,255,0)

I thought doing this would allow me to highlight only the Jobs that match a row in the dataset however when it runs all of the Jobs highlight since this loops through the dataset.
I even attempted to change the on propertyChange script to work as follows but it returns an error:

propertyName = event.source.UserChoice
for row in range(event.source.IncompleteJob.getRowCount()):
	for col in range(event.source.IncompleteJob.getColumnCount()):
		if event.source.UserChoice == event.source.IncompleteJob.getValueAt(row, col):
			event.source.background = (255,255,0)

Any suggestions on what I am doing wrong?

I don’t see any if blocks that limit execution to just the particular property of interest. Unless that is what you are trying to do with the assignments to propertyName?

Your code should look like this:

if event.propertyName == 'UserChoice':
    # do stuff for the UserChoice property

if event.propertyName == 'SomeOtherProp':
    # do stuff for the SomeOtherProp property
2 Likes

Hmm maybe I am misunderstanding how the propertyName part works. I thought that it had to be assigned to a specific property like that in order to keep the script from firing on every property change that occurs.

I’ll also assume that the ‘UserChoice’ in the if block is supposed to be an actual value like an integer (the resulting integer from the dropdown list) and not the event.source.UserChoice, so the following code wouldnt do anything helpful.

propertyName = event.source.UserChoice
if event.propertyName == event.source.UserChoice:
	for row in range(event.source.IncompleteJob.getRowCount()):
		for col in range(event.source.IncompleteJob.getColumnCount()):
			event.source.background = (255,255,0)

So what I am trying to get to happen is I select a username from a dropdown list (or the option of All) and the template background changes when the specified user has IncompleteJobs noted from a mySQL Database. So if I have 10 jobs, only jobs that are assigned to that user and incomplete should be highlighted while the others stay the default color. If I choose All, then any Incomplete Job would be highlighted regardless of who its assigned to.

(I get the feeling I am going about accomplishing this the wrong way but I am not certain).

Yes, you are misunderstanding. You don’t assign to it. The event system supplies it as part of the event object. Look at examples in the manual and all over this forum.

1 Like

event.propertyName will have the name of the property that changed which caused the propertyChange event to fire. You need to filter out properties that you aren’t interested in. In this case, you are only interested in when the UserChoice property changes.

Thus, the first line in the propertyChange script should be

if event.propertyName == 'UserChoice':

Now, the code you have supplied would only ever change the Templates Background color. There is no other option.

The template has no knowledge of anything that happens outside of it, unless you provide it. The template needs to have some way of knowing which user it belongs to, and if that user has complete jobs. Presumably the single column in IncolmpleteJobs is some type of user identification that could be equal to the user selection or not. The template would also need some UserId property, in this way you can then search for a match in the template.

I envision something along these lines.

if event.propertyName == 'UserChoice':
    uid = event.source.UserId
    jobs = system.dataset.toPyDataSet(event.source.IncompleteJobs)

    for row in jobs:
        if row[0] == uid:
            event.source.background  = system.gui.color(255,255,0)
            #if we found a match, then there is no need to go further
            break
1 Like

Okay so I havent given this a try as I got pulled to do other work but I see what I was doing wrong and where youre going with your code kinda. However,

the single column I was using was each of the jobnumbers that the user was assigned to.
So if someone chose user 1 and they were assigned to jobnumbers 10, 15 and 17, but 17 was complete the table would populate with 10 and 15 only.

So I got to give that a try finally, however it doesnt quite seem to work but it maybe close as I see where you going with it.
The template doesnt “belong” to a specific person. Several people could have an IncompleteJob on the same template.

There will need to be some way for the template to determine if the who is assigned to a job, and if that job is complete.

There is no other way to filter. I don’t know enough about your schema to provide any thing more concrete as far as scripting goes. If you can provide some information on what you have tried, we may be able to help more.

Okay so here is what I am working with. I have a Vision Template here that looks similar to this:

As you can see I have two Template Parameters and a single Internal Property. The number after “Job Area #” is controlled by the JobNum parameter and the IncompleteJobs property is a dataset that polls from a Named Query:

select job_number
from jobs
where complete is null and user_id = :userchoice

and returns a table like this (if I need to include the user_id in the actual dataset table I can but I dont think it is necessary):
image

I am looking to use a on property change script to change the background color based on the dataset and the job_numbers that are returned within each row. So if on another screen I have 30 of these templates and a dropdown list of users. If I select user id 1 (like in the picture), then since the dataset returned job_number 10 and 1, the Job Area templates 1 and 10 would have a different background color than the rest.

I have a feeling I am just making this more complicated than it needs to be but even going back and watching IU videos and searching the forums for similar posts but for whatever reason I cannot seem to understand how to get it to work properly.

Also if there is a better way to accomplish this as in binding directly to the Background Color appearance property somehow, please by all means mention it. I was just using scripting because I dont know how else to work with a dataset since I dont actually have a table component on my template and dont work with datasets too often.

Okay, I believe I understand what you are looking for now.

  • UserChoice comes from a drop down outside of the template
  • A single user can be associated with multiple jobs
  • Each Template is specific to a single job.

If you want to do this in script then I think it is better to have the property change script run based on when the dataset changes, since that is what is truly driving the background color. If you base it on the UserChoice parameter, the dataset may or may not be changed when the script is run.

Try this:

if event.propertyName == 'InclompleteJobs':
    jobId = event.source.jobNum
    jobs = system.dataset.toPyDataSet(event.newValue)

    for row in jobs:
        if row['job_number'] == jobId:
            event.source.background = system.gui.color(255,255,0)
            #job is included in incomplete jobs
            break

I don’t however think this is the best way to do this. The reason is that you are running a query multiple times, when in reality only one is needed.

Consider having the query results passed to the template. You would have a single query that is run when the user choice is made, and is then sent to each template, rather than each template running the query. Now you can use a lookup expression on the template in a binding directly on the Background Color (you can use this binding in either case, however, there are performance reasons to change the way the query is being run).

Something like:

if(lookup({TemplateName.IncompleteJobs},{TemplateName.jobNum},0,'job_number'),color(255,255,0,0),color(255,255,255,0))

The lookup expression will return 0 if the job number is not found in the dataset and 1 if it is. The if expression’s trueReturn can be the color to indicate an incomplete job and the false return the color for a complete job.

This I think is the best and most performant way to product the result you are looking for. The script will work, but generally expressions are more performant, and if you can use a binding over a property change script you should do that.

1 Like

Thanks for all that info I will have to give that alternative using the lookup function a try. I had attempted to use it before a few times but I didnt have any luck.

However, I did sort of get your first set of code to work properly. It does highlight templates based on the user selected with incomplete jobs, however, if I select a different user in the dropdown, it doesnt change the no longer correct templates to the default color (I put an else statement in the script and removed the break that should do it but it just seems to ignore it). But you are correct, I have already noticed a performance issue doing it the way that I have currently, sometimes my Vision Client freezes for a moment upon making a selection in the dropdown.

Never mind you can scratch the part about the code not working properly. I had added an extra line into it that was causing it to stop as soon as it read the first row and not continue if there were more in the dataset.

Would you please share how you get result