Try Built-in Modal Groups

E.g.:

Class dc.test Extends %ZEN.Component.page
{

XData Contents [ XMLNamespace "http://www.intersystems.com/zen" ]
{
<page xmlns="http://www.intersystems.com/zen">
  <tablePane id="tp" sql="select 1 id, '2021-11-03' DT union select 2, '2022-01-24'">
    <column colName="id"/>
    <column colName="DT" link="javascript:zenPage.modalGroupCalendar('#(%query.DT)#');"/>
  </tablePane>
</page>
}

ClientMethod modalGroupCalendar(val) [ Language = javascript ]
{
  var group zenPage.createComponent('modalGroup');
  group.setProperty('onaction','zenPage.calendarAction(group);');
  group.show('Select a date:','calendar',val);
}

ClientMethod calendarAction(group) [ Language = javascript ]
{
  alert("You selected: " group.getValue());
  // SaveOnServer(); !
}

}

Try this:

Class dc.test Extends %ZEN.Component.page
{

XData Contents [ XMLNamespace "http://www.intersystems.com/zen" ]
{
<page xmlns="http://www.intersystems.com/zen">
  <tablePane id="tp" sql="select 1 id, 'a' FollowUp union select 2,'b'">
    <column colName="id"/>
    <column colName="FollowUp" header="FollowUp Comments" width="9%" style="text-align:left;" OnDrawCell="txtFollowUp"/>
  </tablePane>
</page>
}

Method txtFollowUp(
  pTable As %ZEN.Component.tablePane,
  pName As %String,
  pSeed As %StringAs %Status
{
    &html<<textarea name="followup" rows="3" style=" width: 95%;" onchange="zenPage.saveFollowUp(this.value,#(%query("id"))#);">#(%query(pName))#</textarea>>
    Quit $$$OK
}

ClientMethod saveFollowUp(
  val,
  id) [ Language = javascript ]
{
  zenAlert(val,' <-> ',id);
}

}
Set object ##class(%ZEN.proxyObject).%New()
set object.city "New York"
set object.Target "TEST" 
set object.Details "TEST"
set object.RefCode "123"
set object.Reason "123TTTT"

set string=object.%Serialize()

;write string,!

set anotherObj=##class(%ZEN.proxyObject).%New()
do anotherObj.%ZENDeserialize(string)

write anotherObj.Reason ; ==> 123TTTT

codemode = code:

ClassMethod AddWater(
  s,
  = {$lb("",1,22,333,4444,55555,666666,7777777,88888888,999999999)},
  ""As %String
{
 i=1:1:$l(sr=r_$li(t,$e(s,i)+1)
 r
}

codemode = expression:

ClassMethod AddWater(
  s,
  = {"" r="" i=1:1:$l(st=$e(s,is:t r=r_$tr($j(t,t)," ",t)}) As %String CodeMode = expression ]
{
r
}

Required mapping ISCDC.inc from CACHESYS:

Include ISCDC

Class dc.test Abstract ]
{

ClassMethod AddWater(sAs %String
{
  i=$l(s):-1:1 t=$e(s,i),$e(s,i)=$$DC(t,t)
  s
}

}

Those experienced with encryption systems for databases may have concerns about encryption having dire effects on performance, but, with Caché, these concerns are unfounded. Encryption and decryption have been optimized, and their effects are both deterministic and small for any Caché platform; in fact, there is no added time at all for writing to the database.

Managed Key Encryption: Protecting Data on Disk

InterSystems recommends using its encryption management tools:

  • When built-in hardware instructions are available for encryption-related activities, these activities are considerably faster then when using software-based encryption. The encryption management tools use hardware instructions when they are available.
  • The encryption management tools can use keys stored on a KMIP server.
  • The encryption management tools can run in FIPS mode.

About Encryption Management Operations

High-Performance Encryption for Databases in Financial Services (PDF)

But in new Native API for IRIS there are no proxies, just class methods/functions are called from app and I think, it should be pretty the same as calling this methods/functions from terminal window.

Introduction to the Native API

Using .NET Reverse Proxy Objects

The Native API allows you to create instances of ObjectScript classes on InterSystems IRIS and generate Object Gateway proxy objects for them at runtime. Your .NET application can use proxies to work with ObjectScript objects as easily as if they were native .NET objects.

Yes, most likely this is a feature of the API.
Here's what I found about it in the "old" documentation:

In some situations, caching may not be desirable. For example, if an object is opened with Concurrency Level 4 (Exclusive Lock), the lock will not be released until the next server call. To destroy the object immediately, you can call Close() with the optional useCache parameter set to false

Closing Proxy Objects

PS: by the way, for ActiveX, Factory.ForceSync() method serves the same purpose.

I did a test and that's what found out.
It is assumed that the data has already been generated.

COS

Class dc.test Extends %Persistent
{

ClassMethod Checking(CardNo As %StringAs %String
{
  tmp=..%OpenId(CardNo,4)
  "test"
}

}

If executed from the terminal, the lock is removed automatically immediately after the method is completed:

USER>##class(dc.test).Checking("1")
test

C#

// ...
string json = iris.ClassMethodString("dc.test""Checking""1");
 
// here the lock is still present
 
db.ReleaseIRISObjects(); // or iris.ReleaseAllLocks();
 
// here already more is no lock