Text Input Confirmation Box

I have a template with a text input field that I'm using in a template repeater.

I want to display a confirmation dialog box, warning the user that they've "cleared" the text in the box before writing to the tag that it's bound to.

The text property is unidirectionally bound to a (indirect) tag. I have a custom "tag" property that is bidirectionally bound to that same (indirect) tag.

The idea is to check the text property before writing the tag, like so:

if event.propertyName == 'text':
	if event.newValue == '' and event.oldValue:
		if system.gui.confirm('<html>Removing name from list will revert any tanks with this name to the default value', 'Warning', True):
			event.source.tag = event.source.text
			
	else:
		event.source.tag = event.source.text

However, when the window with the template repeater starts up I immediately get one popup for each instance in the repeater.

What's the correct way to do this so that the popup only appears when the text is changed by the user?

Bind the input field's text to the custom property, not indirectly to the same tag. Then, in your change event, compare the new text value to the custom property. When those are different, it is a user entry.

Ok, so I put the script in the wrong place...

I also forgot to mention that the indirect tag is actually bound to a root container custom prop first. Not sure if that matters.

So tag <-> nameC <-> Text Field.tag and -> Text Field.tag

Instead I should use tag <-> nameC <-> Text Field.tag -> Text Field.text ?

That's the way I have it and I still get a popup right when the window opens.

Show your code. (I suspect you are still checking against oldValue. Don't do that.)

Root Container custom prop (nameC)
image

Text Field custom prop (tag):
image

Text Field text prop:

def Table_Row.Text Field.text.propertyChange()
	if event.propertyName == 'text':
		if event.newValue == '' and event.oldValue:
			if system.gui.confirm('<html>Removing commodity from list will revert any bins with this commondity to the default value.', 'Warning', True):
				event.source.tag = event.source.text
		else:
			event.source.tag = event.source.text

Why not check old value? I added that in there in case the oldValue was null or '', then we can ignore the change.

edit: it's my else isn't it? The else is catching it at startup and setting it to none and then back to ''

Even without checking against the oldValue I still get the same behavior.

if event.propertyName == 'text':
	if event.newValue == '':
		if system.gui.confirm('<html>Removing commodity from list will revert any bins with this commondity to the default value.', 'Warning', True):
			event.source.tag = event.source.text
	else:
		event.source.tag = event.source.text

The binding flow from a tag updates your .tag prop before the .text prop's unidirectional binding delivers there. So, when coming from the tag, the text prop's new value is equal to the .tag prop's value. Only when .text comes from user input can it be different from .tag.

No other check is necessary or sufficient.. Your code doesn't even perform this minimum comparison.

As stated in my first suggestion:

Emphasis added.

Ok, so I need to also compare against the tag's value?

if event.propertyName == 'text':
	if event.newValue == '' and not ( event.newValue == event.source.tag ):
		if system.gui.confirm('<html>Removing commodity from list will revert any bins with this commondity to the default value.', 'Warning', True):
			event.source.tag = event.source.text
	else:
		event.source.tag = event.source.text

no change

Something like this:

if event.propertyName == 'text':
	if event.newValue != event.source.tag:
		if not event.newValue:
			if system.gui.confirm('<html>Removing commodity from list will revert any bins with this commondity to the default value.', 'Warning', True):
				event.source.tag = event.source.text
		else:
			event.source.tag = event.source.text

Also, since tags often startup with a null, you may need an extra custom property that coalesces nulls to empty strings. Then bind .text to that intermediate custom prop and compare to it instead of .tag.

Ok, so the popup doesn't open right away, but now when I change the text from '' to "test" (and press enter) the tag doesn't get updated

if event.propertyName == 'text':
	if event.newValue != event.source.tag and event.source.tag:
		if event.newValue == '':
			if system.gui.confirm('<html>Removing commodity from list will revert any bins with this commondity to the default value.', 'Warning', True):
				event.source.tag = event.source.text
		else:
			event.source.tag = event.source.text

Why would I need to coalesce to an empty string? event.source.tag results in false if it's empty string or null

  1. Your code is not like my code.

  2. Because a null is not equal to an empty string.

1 Like

It's pretty similar.

I changed not event.newValue to event.newValue == '' and added and event.source.tag

I've used your code directly, and added the coalesce as well.

if event.propertyName == 'text':
	if event.newValue != event.source.tag:
		if not event.newValue :
			if system.gui.confirm('<html>Removing commodity from list will revert any bins with this commondity to the default value.', 'Warning', True):
				event.source.tag = event.source.text
		else:
			event.source.tag = event.source.text

Text Field.text is now bound to Text Field.tagNN which is an expression binding to nameC

coalesce({Table_Row.nameC},'')

Same result

edit: need to compare against the coalesced value, not the tag

if event.propertyName == 'text':
	if event.newValue != event.source.tagNN:
		if not event.newValue :
			if system.gui.confirm('<html>Removing commodity from list will revert any bins with this commondity to the default value.', 'Warning', True):
				event.source.tag = event.source.text
			else:
				event.source.text = event.source.tag
		else:
			event.source.tag = event.source.text

this works now