For completeness, here's an extension of the above example that actually works the way you'd expect (using PublicList to handle scope, and New to avoid leaking any variables):

Class DC.Demo.Indirection
{

ClassMethod Driver() [ PublicList = x ]
{
    New x
    Do ..Run()
    Do ..RunSets()
    Do ..Run()
}

ClassMethod Run() [ PublicList = x ]
{
    Set x = 5
    Try {
        Write @"x"
    } Catch e {
        Write e.DisplayString()
    }
    Write !
    Try {
        Xecute "write x"
    } Catch e {
        Write e.DisplayString()
    }
    Write !
}

ClassMethod RunSets() [ PublicList = x ]
{
    Set x = 5
    Set @"x" = 42
    Write x,!
    Xecute "set x = 42"
    Write x,!
}

}

Results:

USER>d ##class(DC.Demo.Indirection).Driver()
5
5
42
42
5
5
 
USER>w

USER>

But that doesn't mean it's a good idea to do things like this.

This can be done with the requiredMessage property of %ZEN.Component.control. There are two ways to accomplish this:

1. Just add the requiredMessage attribute

Class DC.Demo.ZenLocalization Extends %ZEN.Component.page
{

XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ]
{
<page xmlns="http://www.intersystems.com/zen">
<form>
<text label="Descrição" required="true" requiredMessage="obrigatório." />
<submit caption="Enviar" />
</form>
</page>
}

}

Problem is, you'd need to do that in a lot of different places. Instead, you could...

2. Use custom components that subclass built-in control types.

Sample component:

Class DC.Demo.Component.text Extends %ZEN.Component.text [ System = 3 ]
{

/// Feel free to customize this.
Parameter NAMESPACE = "https://community.intersystems.com/post/change-language-required";

/// Value displayed in alert box by the form <method>validate</method>
/// method when this control is required and does not have a value.<br>
/// This is a localized value.
Property requiredMessage As %ZEN.Datatype.caption [ InitialExpression = "obrigatório." ];

}

Sample page using component:

Class DC.Demo.ZenLocalization Extends %ZEN.Component.page
{

XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ]
{
<page xmlns="http://www.intersystems.com/zen" xmlns:custom="https://community.intersystems.com/post/change-language-required">
<form>
<custom:text label="Descrição" required="true" />
<submit caption="Enviar" />
</form>
</page>
}

}

I was hoping there would be a way to use Zen's localization features to do this, but it seems like that isn't an option, unfortunately;"required." is hard-coded as the InitialExpression for requiredMessage in %ZEN.Component.control, and may only be localized within a page using the component if a non-default value is specified.

Most of the time, you don't really need to use XECUTE/indirection/etc - there is usually a better way to accomplish the same thing. Furthermore, in modern coding practices, XECUTE and name indirection probably will not work the way you expect, because they can only access public variables (not those in the scope of your method). For example, given the following class:

Class DC.Demo.Indirection
{

ClassMethod Run()
{
    Set x = 5
    Try {
        Write @"x"
    } Catch e {
        Write e.DisplayString()
    }
    Write !
    Try {
        Xecute "write x"
    } Catch e {
        Write e.DisplayString()
    }
}

ClassMethod RunSets()
{
    Set x = 5
    Set @"x" = 42
    Write x,!
    Xecute "set x = 42"
    Write x,!
}

}

The output when run in terminal is:

USER>Do ##class(DC.Demo.Indirection).Run()
<UNDEFINED> 9 zRun+3^DC.Demo.Indirection.1 x
<UNDEFINED> 9 zRun+9^DC.Demo.Indirection.1 x
USER>d ##class(DC.Demo.Indirection).RunSets()
5
5
USER>d ##class(DC.Demo.Indirection).Run()
42
42

Your code certainly should not rely on such scoping behavior. There are ways around this (for example, adding  [ PublicList = x ] to the method signature, using New, etc.), but they are messy and difficult to understand and maintain.

In your particular case, using a local array would probably be a better approach - for example:

set x(counter) = DIAGS

Although if you provided more context for why you think you need to dynamically set variables, the community might have other suggestions.

There was an issue with database compaction in 2014.1.1 that could cause database degradation - see this alert: https://www.intersystems.com/support-learning/support/product-news-alerts/support-alert/alert-database-compaction/

Given that, I would recommend contacting the experts in the Worldwide Response Center (InterSystems Support) to help investigate. Running an integrity check on the database you compacted would be a good start - see https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCDI_integrity#GCDI_integrity_verify_portal.

Another slightly more lightweight approach:

Class DC.Demo.combobox Extends %ZEN.Component.combobox [ System = 3 ]
{

Parameter NAMESPACE = "http://community.intersystems.com/demo";

/// Notification that this component is about to become modal.
ClientMethod onStartModalHandler(zindex) [ Language = javascript ]
{
    this.invokeSuper('onStartModalHandler',arguments);
    this.fixLinks(this.getDropDownDiv());
}

/// Look for all children of specified element, and change links with href="#" to also have onclick = "return false;"
ClientMethod fixLinks(element) [ Language = javascript ]
{
    for (var i = 0; i < element.children.length; i++) {
        this.fixLinks(element.children[i]);
    }
    if (element.getAttribute("href") == "#") {
        element.onclick = function() { return false; };
    }
}

}

We specifically chose not to support this capability in Atelier, other than for the special case of launching web pages. As an implementation of Studio Source Control, running an executable on the client only makes sense in cases where the "server" and the "client" are always the same, and for that model the source control plugins publicly and freely available in the Eclipse ecosystem are far superior in terms of support and usability.

I would be interested to hear more details of your use case. What version control system are you using? Git?

(Note to other readers: "UserAction = 3" and other details of the Studio Extension framework are documented here.)

There are two good approaches to this, both relying on an onchange event handler on the first dataCombo.

The first, simpler solution would be to just have an onchange event handler set the value directly:

<dataCombo id="Grupo_Producto" name="Grupo_Producto" dataBinding="bdGrupo" size="40" 
 label="(*) Grupo" dropdownWidth="400" dropdownHeight="100" loadingMessage="Cargando..."
 columnHeaders="Codigo, Nombre"
 queryClass="Innova.CL.Core.BD.Configuracion.Operacional.Grupo" queryName="obtieneGrupoProd"
 sqlLookup="SELECT Nombre FROM Innova_CL_Core_BD_Configuracion_Operacional.Grupo Where ID = ?"
 onchange="zen('Linea_Producto').setProperty('parameters',1,zenThis.getValue());"
 > 
</dataCombo>

However, if you have multiple components on the page that depend on the current value of Grupo_Producto, it might be simpler to use a property of the page that has the value of the component copied to it when that value changes. This is handy because you can reference the value in a Zen expression, e.g., #(%page.GrupoProducto)#, rather than needing to copy the same value to lots of places. Here is an example with two dataCombos in the SAMPLES namespace:

Class DC.Demo.ComboBox Extends %ZEN.Component.page
{

Property homeState As %ZEN.Datatype.string;

XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ]
{
<page xmlns="http://www.intersystems.com/zen">
<dataCombo id="homeState" label="State"
sql="select distinct Home_State from Sample.Person order by Home_State"
onchange="zenPage.dataComboChanged(zenThis)"
/>
<dataCombo id="homeCity" label="City"
sql="select distinct %exact Home_City from Sample.Person where Home_State = ? order by Home_City">
<parameter value="#(%page.homeState)#" />
</dataCombo>
</page>
}

ClientMethod dataComboChanged(component) [ Language = javascript ]
{
    // Update the page property's value.
    // Note: page property and component ID don't necessarily need to match, but it's convenient if they do.
    // (Imagine a cascade of dataCombos with dependent values.)
    zenPage.setProperty(component.id,component.getValue());
    
    // Possibly also call refreshContents() on components referencing properties that may have changed,
    // and/or clear values that may have been invalidated by the change.
    // dataCombo does not need this, but other components (e.g., tablePane) would.
}

}

I can't speak to a fix, but a few thoughts:

  • There is a critical difference between Studio and Atelier projects: Atelier projects are not even present on the server / in the database. This may prevent them from being used interchangeably with Studio projects for purposes of your source control extension and change control processes.
    • Because of this difference, it would probably not be a good idea to populate ^||%Studio.Project with the name of the project in Atelier.
  • One option might be updating your source control extension (perhaps adding new menu items and UserAction/AfterUserAction handling for them) to support creating a %Studio.Project and associating/dissociating files with one, even from Atelier. This would support mixed use of Studio and Atelier and make migration simpler.
  • If you want to be able to detect in your source control extension code whether it is being called from Studio or Atelier, you can look at the StudioVersion property (defined in %Studio.Extension.Base). Particularly, this will contain the string "Atelier" if invoked from Atelier.

A nice enhancement for Atelier might be supporting a project definition that is shared between the client and server.

The current Atelier project is not exposed. What is your intended use case for it?

Regarding $Username - I suspect that the /api/atelier web application on your instance has only "Unauthenticated" selected under "Allowed Authentication Methods." If you change this to "Password" only and restart Atelier you should see $Username populated correctly.

If you're really interested in efficiency, one option might be put the list into a local array with $ListNext and then iterate over the array in reverse (either with a decrementing counter in a for loop, or using $order(array(sub),-1)). For example, rather than:

For i=$ListLength(tInputList):-1:1 {
    Set tValue = $ListGet(tInputList,i)
    // Do something with tValue
}

You could use something like the following (which accounts for null values in the $ListBuild list by skipping that index in the integer-subscripted array):

Kill tArray
Set tPointer = 0
While $ListNext(tInputList,tPointer,tValue) {
    If $Data(tValue) {
        Set tArray($i(tArray)) = tValue
    } Else {
        Set tArray = tArray + 1
    }
}

Set tKey = ""
For i=$Get(tArray):-1:1 {
    If $Data(tArray(i),tValue) {
        // Do something with tValue
    }
}

For "large enough" lists (the threshold for this depends on the length of the list elements), the second approach will be faster. (In testing, this performs better than putting the reversal of the original $ListBuild list into another $ListBuild list.)

More generally speaking: if you have a list that you only append to the end of (rather than needing to insert/shift elements randomly in the middle of it), and will need to iterate over it in reverse, a local array with integer subscripts is a better choice of data structure than a $ListBuild list.

That's not actually the case. If you look at the .INT code for the generated %CreatePage method of a Zen page with &#65292; in columnHeaders (I tested this out with ZENDemo.FormDemo in the SAMPLES namespace), you'll see something like:

Set dtCmb7.columnHeaders="House number,apartment"

The numeric character reference is converted to the Unicode character when the Zen XML is imported; the reason &#44; doesn't work is that it's converted to a plain old comma, which is no different from just putting a comma in the XML in terms of what Zen does with it.

To expand on Sean's answer from the comment section, perhaps try the numeric character reference for the fullwidth comma:

columnHeaders="House number&#65292;apartment"

Another option would be to create a custom Zen component that extends %ZEN.Component.dataCombo and handles delimiters differently for the columnHeaders property. Unfortunately, this approach would require overriding %DrawDropDownContents, which is an enormous method and flagged as [Internal] - best avoided, in my opinion!