Engineer Blog: Sending Emails in OutSystems

In this engineer blog, I introduce the topics I study and work on in my daily learning.

Today’s Topic: Sending Emails in OutSystems

In OutSystems, you can send emails from screens or batch processes by using your own mail server.
In this post, I’ll walk through how to configure the environment and how to create a test screen.

Preparation: What You Need to Have Ready in Advance

OutSystems alone cannot send emails.
You need to prepare an email server in advance and make note of the following information:
#1.SMTP server
#2.SMTP port number
#3.Username (email address)
#4.Password
Depending on the type of mail server, there may also be options such as ‘restrictions on sending from overseas.’
If such a setting exists, be sure to turn it off.
Otherwise, you may encounter errors like ‘Sender address rejected: Incorrect country code US,’ which can prevent email delivery even when your configuration is correct.

Step 1: Environment Setup

First, enter the mail server information that OutSystems will use from Service Center. In Service Studio, click the gear icon shown below to access Service Center.

After logging in, open the email server settings by selecting Administration > Email

Enter the following information as shown below:
・SMTP Server: Preparation #1
・SMTP Port: Preparation #2
・Username: Preparation #3
・Password: Preparation #4
・Default Sender Email: Preparation #3
・Redirect Emails To Test List: Optional
 *This option redirects emails to the Test List Addresses even if the logic specifies a different recipient.
  Enable this for testing purposes.
・Test List Addresses: Optional
 *Specify the email address to which messages will be redirected.

After entering all the information, click the Save and Apply Settings to the Factory button to apply the configuration.
 *Note: Simply clicking ‘Save’ does not activate the email settings.
  Also, the Password field will appear blank after saving, but as long as the configuration is correct, emails will still be sent without any issues.

Step 2: Creating the Logic

This time, we will create a simple test screen and the logic for sending emails, as shown below.

① Test Screen: Enter the recipient, subject, and message body, then click the SendMail button to send an email based on the entered values.
② Email Body Screen: The value received through the InBody input parameter is displayed directly as the email body.
③ Client Action: This action is triggered when the SendMail button is clicked. It calls the server action responsible for sending the email.
④ Server Action: This action is called from the Client Action. It sends the email according to the layout created in step ②

Testing the Functionality

Once the 1‑Click Publish completes successfully, open the screen and try running it.

Example Input: To verify the redirect behavior, enter an email address in the top recipient field that is different from the one configured in Test List Addresses.
The email that was actually received at the address specified in Test List Addresses.

The top section shows the value of the Default Sender Email.
You can also see that the recipient field contains the address entered on the screen (which is different from the one specified in Test List Addresses), confirming that the redirect feature is working as expected.

Email sending logs in Service Center.

From Monitoring > Email, you can check the subject, sender/recipient email addresses, email size, and status.
In particular, the status may show Sent (success), Pending (waiting), or Error (failed). When an error occurs, you can click the Detail link to view the error information, which helps identify the cause.

Conclusion

With the above steps, you are now able to send emails from OutSystems.
However, one important point to keep in mind is that the actual email‑sending mechanism ultimately depends on the mail server.
Be sure to review the mail server settings carefully to ensure they meet your requirements—for example, limits on the number of emails that can be sent per hour, or restrictions on sending or receiving emails from specific addresses.

Stay tuned for the next developer blog…

技術者ブログ:(Outsystems)メールを送信する

技術者ブログとして日ごろ取り組んでいる学習内容を紹介します。

今回のテーマ:(Outsystems)メールを送信する

Outsystemsでは、各自で用意したメール送信サーバを用いることで、画面・バッチよりメールを送信することが出来ます。
今回は、環境設定と、テスト用画面の作成方法について紹介します。

準備:予め用意しておくもの

Outsystems単独ではメールを送信することはできません。
予め、メール送信サーバを調達し、以下の情報をメモしておきましょう:
#1.送信サーバ(SMTP)
#2.送信サーバのポート番号
#3.ユーザー名(メールアドレス)
#4.パスワード
また、メール送信サーバの種類にもよりますが、気を付けるべき点として「海外からの送信制限」のようなオプションがある場合、Offにしておきましょう。
“Sender address rejected: Incorrect country code US”のようなエラーが発生し、設定が正しいのにメールが送信できない場合があります。

手順1:環境設定

まず、ServiceCenterより、Outsystemsが使用するメール送信サーバの情報を入力します。
ServiceStudioより、下記歯車アイコンを押下し、ServiceCenterへアクセスしてください。

ログイン後、メニューよりAdministration>Emailとリンクを押下することで、メール送信サーバの設定画面が開きます。

それぞれ、次のように入力します:
・SMTP Server:準備#1
・SMTP Port:準備#2
・Username:準備#3
・Password:準備#4
・Default Sender Email:準備#3
・Redirect Emails To Test List:任意
 ※ロジックで宛先を指定しても、後述するTest List Addressesへメールをリダイレクトする機能です。
  動作確認のため、有効化しておきます。
・Test List Addresses:任意
 ※リダイレクト先のメールアドレスを設定します。

一通り入力し終えたら、Save and Apply Settings to the Factoryボタンを押下し、入力した設定値を反映しましょう。
 ※Saveするだけではメール設定は有効になりません。
  また、Save後Password欄は空欄になりますが、正しく設定できていればメールは送信できますので問題ありません。

手順2:ロジック作成

今回は、下記のようなシンプルなテスト画面、およびメール送信機能のロジックを作成します。

①テスト画面:宛先、件名、本文を入力し、SendMailボタンを押下することで入力値に基づきメールが送信される。
②メール本文画面。引数InBodyで受け取った値をそのままメール本文に表示する。
③ClientAction:SendMailボタン押下時に呼ばれる。メール送信用サーバアクションを呼び出す。
④ServerAction:ClientActionから呼び出される。②で作成したレイアウトに従い、メールを送信する。

動作確認

1-click publishが正常終了したら、画面を開いて動かしてみましょう。

入力例:リダイレクト動作確認のため、最上段の宛先メールアドレスには、Test List Addressesで設定したものと異なるメールアドレスを入力する。
実際にTest List Addressesに記載のメールアドレスにて受信したメール。

最上段にはDefault Sender Emailの値が記載されています。
また、宛先欄には画面で入力した宛先(≠Test List Addressesに記載のメールアドレス)が記載されており、リダイレクトが期待通りに機能していることが読み取れます。

ServiceCenterにおけるメール送信ログ。

Monitoring>Emailより、件名・送信元/先メールアドレス・メール容量・ステ―タスが確認できます。
特に、ステータスはSent(送信完了)・Pending(待機中)の他にError(送信失敗)になる場合があり、この時表示されるDetailリンクからエラー内容を確認できるため、原因の特定に役立てることができます。

まとめ

以上の手順にて、Outsystemsよりメールを送信することができるようになりました。
ただし、一つ気を付けておかなければならないのは「あくまでメール送信の仕組み自体はメール送信サーバに依存している」ことです。
時間当たりの送信可能メール数や、特定のメールアドレスから/へのメール送受信を許可しない設定など、要件に合わせたカスタマイズが送信サーバ側の設定をよく確認しましょう。

それでは、次回の技術者ブログをお楽しみに…。

Engineering blog – 5 Useful Java Features in Modern Java

Java has evolved significantly over the past decade. While many developers still associate Java with verbose syntax and heavy boilerplate, modern Java versions (Java 8 and beyond) introduced powerful features that make development cleaner, safer, and more expressive.

In this article, we’ll explore five useful Java features that every developer should know and start using today.

1. Lambda Expressions

Lambda expressions allow you to write concise, functional-style code. They eliminate the need for anonymous classes and make your code easier to read.

Before Java 8:

Runnable r = new Runnable() {
    public void run() {
        System.out.println("Hello World");
    }
};

With Lambda:

Runnable r = () -> System.out.println("Hello World");

Why It’s Useful:

  • Reduces boilerplate code
  • Improves readability
  • Encourages functional programming

Lambda expressions are widely used with Streams, collections, and event handling.


2. Stream API

The Stream API allows you to process collections in a declarative and functional style.

Example:

List<String> names = List.of("Alice", "Bob", "Andrew");

names.stream()
     .filter(name -> name.startsWith("A"))
     .map(String::toUpperCase)
     .forEach(System.out::println);

Benefits:

  • Clear and expressive data processing
  • Supports parallel execution
  • Encourages immutability

Streams make complex data transformations readable and maintainable.


3. Optional Class

Optional helps avoid NullPointerException by explicitly representing a value that may or may not exist.

Example:

Optional<String> username = Optional.ofNullable(getUsername());

username.ifPresent(System.out::println);

Why It Matters:

  • Encourages null-safe coding
  • Makes APIs clearer
  • Reduces runtime errors

Instead of returning null, methods can return Optional<T> to express uncertainty.


4. Records (Java 16+)

Records provide a concise way to create immutable data classes.

Example:

public record User(String name, int age) {}

The compiler automatically generates:

  • Constructor
  • Getters
  • equals() and hashCode()
  • toString()

Advantages:

  • Less boilerplate
  • Immutable by default
  • Ideal for DTOs

Records are perfect for modeling simple data carriers.


5. Switch Expressions

Modern Java allows switch to return values and use arrow syntax.

Example:

String dayType = switch (day) {
    case "Sat", "Sun" -> "Weekend";
    default -> "Weekday";
};

Why It’s Better:

  • More concise syntax
  • No need for break
  • Fewer bugs

Switch expressions improve readability and reduce accidental fall-through errors.


Modern Java focuses on: Cleaner syntax, Safer code and Better developer experience.

If you’re still using older Java patterns, upgrading your style to include these features can dramatically improve your productivity and code quality.

Stay tuned for our next article!

技術ブログ – モダンJavaの便利な機能5選

Javaはこの10年で大きく進化しました。多くの開発者はいまだに、冗長な構文や大量のボイラープレートコードを連想するかもしれませんが、モダンJava(Java 8以降)では、よりクリーンで安全、そして表現力の高い開発を可能にする強力な機能が導入されています。

この記事では、すべての開発者が知っておくべき5つの便利なJava機能を紹介します。

1. ラムダ式(Lambda Expressions)

ラムダ式を使うことで、簡潔な関数型スタイルのコードを書くことができます。無名クラスを使う必要がなくなり、コードの可読性が向上します。

Java 8以前:

Runnable r = new Runnable() {
    public void run() {
        System.out.println("Hello World");
    }
};

ラムダ式を使うと:

Runnable r = () -> System.out.println("Hello World");

メリット:

  • ボイラープレートコードの削減
  • 可読性の向上
  • 関数型プログラミングの促進

ラムダ式は、Stream APIやコレクション操作、イベント処理などで広く利用されています。


 

2. Stream API

Stream APIを使用すると、コレクションを宣言的かつ関数型スタイルで処理できます。

例:

List<String> names = List.of("Alice", "Bob", "Andrew");

names.stream()
     .filter(name -> name.startsWith("A"))
     .map(String::toUpperCase)
     .forEach(System.out::println);

メリット:

  • 明確で表現力の高いデータ処理
  • 並列実行に対応
  • イミュータブルな設計を促進

Streamを使うことで、複雑なデータ変換も読みやすく保守しやすいコードになります。


 

3. Optionalクラス

Optionalは、値が存在するかどうかを明示的に表現することで、NullPointerExceptionを回避するのに役立ちます。

例:

Optional<String> username = Optional.ofNullable(getUsername());

username.ifPresent(System.out::println);

重要なポイント:

  • null安全なコーディングを促進
  • APIの意図が明確になる
  • 実行時エラーの削減

メソッドがnullを返す代わりに、Optional<T>を返すことで、値が存在しない可能性を明確に表現できます。


 

4. Records(Java 16以降)

Recordは、不変なデータクラスを簡潔に作成するための機能です。

例:

public record User(String name, int age) {}

コンパイラが自動的に生成するもの:

  • コンストラクタ
  • Getterメソッド
  • equals()hashCode()
  • toString()

メリット:

  • ボイラープレートの削減
  • デフォルトでイミュータブル
  • DTOに最適

Recordは、シンプルなデータ保持用クラスのモデリングに最適です。


 

5. Switch式(Switch Expressions)

モダンJavaでは、switchが値を返せるようになり、アロー構文(->)も使用できます。

例:

String dayType = switch (day) {
    case "Sat", "Sun" -> "Weekend";
    default -> "Weekday";
};

優れている点:

  • より簡潔な構文
  • breakが不要
  • バグの減少

Switch式は可読性を向上させ、意図しないフォールスルー(fall-through)によるエラーを防ぎます。


 

モダンJavaが目指しているのは、よりクリーンな構文、より安全なコード、そして優れた開発者体験です。

もしまだ古いJavaの書き方を使っているなら、これらの機能を取り入れることで、生産性とコード品質を大きく向上させることができます。

次回の記事もお楽しみに!

Setting Up a Vue 3 Development Environment on Windows Using Cursor

As a tech blog, I’d like to share what I’ve been learning recently.
This time, I’ll walk you through how I set up a Vue 3 development environment using Cursor, a code editor with built-in AI features.

Requirements

・Node.js
・Cursor
・Vue3
・Vue Router

Installing Node.js

Download the installer from the official website
The latest version at the time of writing is 24.12.0 (LTS)
Download the Windows installer

Follow the installation wizard. If you don’t have any specific preferences, just clicking ‘Next’ through all the steps is fine.

You can basically keep clicking ‘Next’ here as well, but if you plan to use various Node.js modules in the future, it’s a good idea to check this option.
However, it’s not necessary for this setup.

That’s it! Node.js is now set up and ready to go.

Installing Cursor

Download the installer from the official website.
The latest version at the time of writing is 2.2.44.
If you don’t have any specific preferences, you can proceed with the default settings during installation.
After installation, you’ll be prompted to log in, so it’s a good idea to create an account on the official website beforehand for a smoother setup.

Adding Extensions to Cursor

Add the following extensions to Cursor

  • Japanese Language Pack for VS Code
    ・Japanese localization
  • npm
    ・Support for npm
  • Npm Intellisense
    ・Auto-completion for npm modules in import statements
  • Vue (Official)
    ・Support for Vue
  • Vite
    ・Support for Vue development server

Creating a Vue 3 Project

Go to File > Open Folder and open the location where you want to create your project.

Open the terminal with [Ctrl + @]

Run the following command in the terminal to create the project

npm create vue@latest

Type ‘y’

Enter your preferred project name and package name.

Select the packages you want to add.

Give it a try

  • TypeScript
    ・Must be added
  • JSX Support
    ・Enables writing Vue in JSX/TSX syntax. Add this if you prefer a React-like style.
    ・Turned off for this setup.
  • Router
    ・Essential for page navigation
    ・Must be added
  • Pinia
    ・State management library
    ・Add if you need to manage login info, user data, or shared state
  • Vitest
    Add if you want to automate unit testing
  • End-to-End Testing
    ・Add if you want to automate tests that include browser interactions
  • ESLint
    ・Linting tool to check code style
    ・Must be added
  • Prettier
    ・Automatically formats your code
    ・Must be added

You’ll be asked whether to enable experimental features. Since we won’t be using them this time, just press Enter to keep the default.

You’ll be asked whether to create the project without sample code.
For this setup, select ‘No’ to include the sample code.

The project creation will begin, and once it’s complete, a project folder will be generated.

Reopen the created project folder in Cursor and run the following command

PS C:\vue3\startupVue> npm install

Once the dependencies are installed, the project setup is complete.

Starting the Vue app

Run the following command to start the development server

npm run dev

If the launch is successful, the following screen will be displayed

You can stop the server by typing [q] in the console.

That’s it! We’ve set up a Vue 3 development environment using Cursor.
If this sparked your interest, try setting it up on your own PC too!

Windows環境のCursorでVue3開発環境を作ってみる

技術者ブログとして日ごろ取り組んでいる学習内容をご紹介します。
今回はAI機能を搭載したコードエディタCursorでVue3の開発環境を作ってみたので紹介します。

必要なもの

・Node.js
・Cursor
・Vue3
・Vue Router

Node.jsのインストール

公式サイトよりインストーラを取得
記事作成時最新は「24.12.0(LTS)」
Windowsインストーラをダウンロード

インストールウィザードに沿ってインストール、特にこだわりがなければすべてNextでOK

以下も基本的にNextで大丈夫ですが、今後Node.jsのいろいろなモジュールを使用した場合は
チェックを入れておくといいです。
今回の環境では不要です。

以上でNode.jsが準備できました。

Cursorのインストール

公式サイトよりインストーラーを取得します。
記事作成時最新は「2.2.44」
とくにこだわりがなければ、インストーラーデフォルト設定のままインストールでOK
インストール後、ログインが求められるのであらかじめ公式サイトのログインからアカウント登録しておくとスムーズに進みます

Cursorに拡張機能の追加

Cursorに以下の拡張機能を追加します

  • Japanese Language Pack for VS Code
    • 日本語化
  • npm
    • npmのサポート
  • Npm Intellisense
    • importステートメント内のnpmモジュール自動補完
  • Vue (Official)
    • Vueのサポート
  • Vite
    • Vue開発サーバーのサポート

Vue3プロジェクトを作成

ファイル > フォルダーを開くでプロジェクトを作成したい場所を開く

[Ctrl + @]でコンソールを開く

コンソールで以下のコマンドを実行しプロジェクトを作成

npm create vue@latest

yを入力

お好きなプロジェクト名、パッケージ名を入力

追加したいパッケージを選択します

実行してみる

  • TypeScript
    • 必ず追加
  • JSX Support
    • JSX/TSX で Vue を書くための機能、React風に書きたい場合は追加
    • 今回はOFF
  • Router
    • 画面遷移に必須
    • 必ず追加
  • Pinia
    • 状態管理ライブラリ
    • ログイン情報・ユーザー情報・共通データなどを扱う場合は追加
  • Vitest
    • 単体テスト自動化するなら追加
  • End-to-End Testing
    • ブラウザ操作を含むテストを自動化するなら追加
  • ESLint
    • コードの書き方チェック
    • 必ず追加
  • Prettier
    • コード自動整形
    • 必ず追加

実験的機能を使うか聞かれる今回は使用しないため初期のままEnter

サンプルコードを省略して作成するか確認されるので今回は「No」を選択し
サンプルコードを追加

プロジェクトの作成が始まり完了するとプロジェクトフォルダが作成される

作成したプロジェクトフォルダをcursorを開きなおし以下のコマンドを実行

PS C:\vue3\startupVue> npm install

依存関係のインストールが完了すればプロジェクトの準備完了

Vueの起動

以下のコマンドを実行すると開発サーバーを実行することができます

npm run dev

起動に成功すると以下の画面が表示される

コンソールに[q]を入力することでサーバーを停止できます

以上、CursorでVue3の開発環境を構築してみました。
興味が持てましたら自分のPCにも構築してみてください。

Engineer Blog – Automatic Column Generation in OutSystems Data Grid

In this engineer blog, I’ll introduce what I’ve been learning recently. This time, I’ll explain automatic column generation in OutSystems Data Grid.

  • OutSystems Data Grid is a spreadsheet-like grid that can be displayed and interacted with within an OutSystems application.
  • This article assumes prior knowledge of OutSystems Data Grid.

Problem Statement

For example, let’s say we have a grid like the one below.

The usual way to create it would be as follows.

  1. Set the data to be displayed into a Structure that matches the grid layout, convert it into a list, transform it into JSON using ArrangeData, and set the resulting JSON as the grid’s data.
  2. Place a column widget on the grid for each column to be displayed, and configure each header, column width, display conditions, and so on.

For a grid with six columns like the one above, it’s not too difficult. However, if the number of columns to display is variable, creating it becomes more challenging.

You need to determine the maximum number of columns to display, then prepare the Structure from step 1 and the column widgets from step 2 to match that maximum number. Additionally, you must control the visibility of each column based on how many you actually want to display. As a result, all the columns up to the maximum exist, but only the desired number of columns are visible.

Especially for step 2, if the grid’s configuration is even slightly complex—such as having merged headers with dynamic labels—the amount of work required increases significantly.

If the maximum number is around 100, it might take some time, but it’s still manageable. However, I once faced a case where the maximum number reached nearly 1,500. At that time, I looked into whether it was possible to generate the grid columns using JavaScript.

As a result of the automatic generation, step 1 of the usual method still needs to be done as is, but step 2 becomes much simpler.

Prerequisites

In a grid like the one below, the columns outlined in red are the target for automatic generation. (The left three columns are placed as usual. The auto-generated columns are on the right.)

The cells in the auto-generated columns will be set to read-only. The column order in the grid will be fixed and cannot be changed.

The data to be displayed in the grid has already been retrieved and is set to the grid as described in step ① above.

The header labels (such as ‘グループ1’, ‘データX’, ‘名名名’, etc.) are dynamic and have already been retrieved in a format that can be passed into JavaScript. (In the sample JavaScript code, these input parts will be shown in bold.)

In the implementation JavaScript, we use a variable called dataGrid. You can obtain dataGrid as shown below. (Let gridId be the ID of the configured grid.)

var dataGrid = OutSystems.GridAPI.GridManager.GetGridById('gridId').provider;

Preliminary Research

From the link below, I found that it’s possible to push columns into dataGrid.columns.

https://www.outsystems.com/forums/discussion/80001/outsystems-data-grid-is-is-possible-to-add-columns-dynamically-on-datagrid/

Upon further investigation of dataGrid, I found that in addition to columns, there is also columnGroups. I thought that by pushing to columnGroups, it might be possible to create grouped, merged header columns.

Implementation Flow

In the ‘On After Fetch’ action after retrieving the data, implement it as follows.

The first column of ‘グループ1’

// Create the element to push
var newColGroup = new wijmo.grid.ColumnGroup (
	{header: 'グループ1', align: 'left', columns: [
		{header: 'データX', align: 'left', columns: [
			{header: '', binding: 'Data1', width: 100, align: 'left', isReadOnly: true}
		]}
	]}
)
// Push newColGroup into columnGroups
dataGrid.columnGroups.push(newColGroup);

The second column of ‘グループ1’

// Create the element to push
var newColGroup = new wijmo.grid.ColumnGroup (
	{header: 'データ1', align: 'left', columns: [
		{header: '名名', binding: 'Data2', width: 100, align: 'left', isReadOnly: true}
	]}
)

// Push newColGroup into the columns of the target columnGroup
// columnGroups[3] refers to the created "Group 1", which is at index 3 in columnGroups
dataGrid.columnGroups[3].columns.push(newColGroup);

the ‘グループ2’ column

// Create the element to push
var newColGroup = new wijmo.grid.ColumnGroup (
	{header: 'グループ2', align: 'left', columns: [
		{header: 'データV', align: 'left', columns: [
			{header: '名名名', binding: 'Data3', width: 100, align: 'left', isReadOnly: true}
		]}
	]}
)

// Push newColGroup to columnGroups
dataGrid.columnGroups.push(newColGroup);

As shown above, grouped columns with merged headers are created one by one.
By adjusting the structure of newColGroup and the target of the push accordingly, it should be possible to create column groups with different structures.

additional support

When automatically generating columns, the following two points must be taken into consideration.

  • The variable dataGrid represents the grid obtained as a JavaScript object. At the time the ‘On After Fetch’ action is executed after data retrieval, the grid must already exist. One way to handle this is to set the data retrieval action’s timing to ‘Only on Demand’ and execute it in the ‘OnReady’ action.
  • If the grid contains columns with editable cells, a post-edit check is performed on the entire row to determine whether any cells were edited. However, if this check tries to access the automatically generated columns, it will result in an error. (In the grid used as an example in this article, the ‘Settings’ column is editable.)

To handle this, adjust the edit check in the grid’s ‘OnInitialize’ action using JavaScript as shown below.

// Regular cell edit check
var originalCheck = OutSystems.GridAPI.GridManager.GetGridById('gridId').features.dirtyMark._isDirtyCell;

// Adjust the check
// Immediately treat cells in auto-generated columns as unedited
// Since columns with index 3 and above are auto-generated, control with "columnIndex > 2"
var newCheck = function (rowIndex, columnIndex) {
	if (columnIndex > 2) {
		return false;
	} else {
		var checkResult = originalCheck.call(this, rowIndex, columnIndex);
		return checkResult;
	}
}

// Apply the adjusted check to the grid
OutSystems.GridAPI.GridManager.GetGridById('gridId').features.dirtyMark._isDirtyCell = newCheck;

Stay tuned for the next developer blog.

技術者ブログ – OutSystems Data Gridにおける列自動生成

技術者ブログとして日ごろ取り組んでいる学習内容をご紹介します。今回は、OutSystems Data Gridにおける列自動生成について説明します。

  • OutSystems Data Gridは、OutSystemsのプログラムの中で表示・操作できる、Excelのようなグリッドになります。
  • 本記事は、OutSystems Data Gridについての知識を前提とします。

問題設定

例えば、以下のようなグリッドがあるとします。

通常の作成方法は、以下になると思います。

  1. 表示するデータを、グリッドの構造に合わせたStructureに設定して、リスト化して、ArrangeDataでJSONの変換して、結果のJSONをグリッドのデータとして設定する
  2. グリッドに、表示する列の件数分、列ウィジェットを配置して、それぞれのヘッダ、列幅、表示条件などを設定する

上記のような、列が6件のグリッドの場合、さほど難しくないと思いますが、表示したい列の数が可変の場合、作成が難しくなります。

表示できる最大数を決定して、「1.」のStructureの項目数と、「2.」の列ウィジェットは、それぞれ、その最大数の件数分を用意しなければなりません。そして、各列の表示条件を、表示したい個数に合わせて制御しなければなりません。結果として、最大数の件数分の列が存在しているが、表示した件数分のみが見えています。

特に「2.」については、グリッドの仕様が少しでも複雑(重複ヘッダで、その文言が動的など)でしたら、必要な作業量が著しく増えていきます。

決定した最大数が、例えば100件ぐらいでしたら、多少時間がかかりますが、できなくはない程度になると思いますが、以前、最大数が1500件近くになる場合に直面したことがあります。その際に、グリッドの列をJavaScriptで生成できないか、調べてみました。

自動生成の結果、上記の通常の作成方法の「1.」は、そのまま実施しなければなりませんが、「2.」の方が、簡単になります。

前提

以下のようなグリッドでは、赤枠の列を自動生成の対象します。(左3列は、通常通り配置した列となります。自動生成の列は、右となります。)

自動生成の列のセルを編集不可とします。グリッドの列順を変更不可とします。

グリッドで表示するデータは、取得済みで、上記の①のようにグリッドに設定します。

ヘッダの文言(「グループ1」、「データX」、「名名名」など)を可変として、取得済みで、JavaScriptにインプットできる形で持っています。(実装例のJavaScriptコードの中で、このようなインプット部分を太文字にします。)

実装のJavaScriptで、dataGridという変数を使います。dataGridは、以下のように取得できます。(gridIdは、設定したグリッドのIdとします。)

var dataGrid = OutSystems.GridAPI.GridManager.GetGridById('gridId').provider;

事前調査

以下のリンクで、dataGridのcolumnsに列をpushできることが分かりました。

https://www.outsystems.com/forums/discussion/80001/outsystems-data-grid-is-is-possible-to-add-columns-dynamically-on-datagrid/

dataGridを細かく調査すれば、columnsの他に、columnGroupsもあると分かって、columnGroupsに対するpushで、グループ化された重複ヘッダの列群を作成できるのではないかと考えました。

実装の流れ

データ取得後のOn After Fetchアクションで、以下のように実装していきます。

「グループ1」の最初の列

// pushする要素を作成
var newColGroup = new wijmo.grid.ColumnGroup (
	{header: 'グループ1', align: 'left', columns: [
		{header: 'データX', align: 'left', columns: [
			{header: '', binding: 'Data1', width: 100, align: 'left', isReadOnly: true}
		]}
	]}
)

// newColGroupをcolumnGroupsにpush
dataGrid.columnGroups.push(newColGroup);

「グループ1」の二つ目の列

// pushする要素を作成
var newColGroup = new wijmo.grid.ColumnGroup (
	{header: 'データ1', align: 'left', columns: [
		{header: '名名', binding: 'Data2', width: 100, align: 'left', isReadOnly: true}
	]}
)

// newColGroupを対象のcolumnGroupsのcolumnsにpush
// columnGroups[3]は、作成した「グループ1」はcolumnGroupsの中でインデックス3のため
dataGrid.columnGroups[3].columns.push(newColGroup);

「グループ2」の列

// pushする要素を作成
var newColGroup = new wijmo.grid.ColumnGroup (
	{header: 'グループ2', align: 'left', columns: [
		{header: 'データV', align: 'left', columns: [
			{header: '名名名', binding: 'Data3', width: 100, align: 'left', isReadOnly: true}
		]}
	]}
)

// newColGroupをcolumnGroupsにpush
dataGrid.columnGroups.push(newColGroup);

上記のように、グループ化された、重複ヘッダの列を1つずつ作成していきます。newColGroupの構造、push先のところを適宜調整すれば、異なる構造の列群を作成できると思われます。

追加対応

列自動生成にあたり、以下の2点を留意しなければなりません。

  • 変数dataGridは、グリッドをJavaScriptオブジェクトとして取得したものになります。データ取得後のOn After Fetchアクションが実行される時点で、グリッドが存在しなければなりません。一つの対応方法として、データ取得アクションのタイミングをOnly on Demandに設定して、OnReadyアクションで実行することができます。
  • グリッドに、セルが編集可能な列がある場合、セル編集後、行全体に対して実施されるセル編集有無チェックは、自動生成列のセルをチェックしようとしたら、エラーとなります。(本記事で例として使ったグリッドでは、「設定」列が編集可能とします。)

対応するには、グリッドのOnInitializeアクションのJavaScriptで、以下のように編集有無チェックを調整します。

// 通常のセル編集有無チェック
var originalCheck = OutSystems.GridAPI.GridManager.GetGridById('gridId').features.dirtyMark._isDirtyCell;

// チェックを調整
// 自動生成列のセルを、即座に編集なしとする
// 列インデックス3以上は、自動生成の列のため、「columnIndex > 2」で制御
var newCheck = function (rowIndex, columnIndex) {
	if (columnIndex > 2) {
		return false;
	} else {
		var checkResult = originalCheck.call(this, rowIndex, columnIndex);
		return checkResult;
	}
}

// 調整したチェックをグリッドに設定
OutSystems.GridAPI.GridManager.GetGridById('gridId').features.dirtyMark._isDirtyCell = newCheck;

次回の技術者ブログをお楽しみに。

Engineer Blog: Generating PDFs Using Ultimate PDF in OutSystems

As part of our engineer blog, we’d like to share what we’ve been learning day by day.
This time, it’s Team 2, focusing on low-code development.

This Time’s Theme: ‘PDF Output Using Ultimate PDF

This time, we’ll show you how to export screen data within OutSystems as a PDF.

What is Ultimate PDF?

Ultimate PDF is one of the Forge components available in OutSystems. It allows you to export web pages (HTML + CSS) as PDFs.
For example, you can generate PDFs of formatted content like invoices, reports, business cards, and forms.

Installing Ultimate PDF

Launch Service Studio, search for ‘Ultimate PDF’ via Browse Forge, and install it.

Adding References to the Module

Open the module you want to use, go to Manage Dependencies (CTRL+Q), select the necessary elements from Ultimate PDF, and click the Apply button.
(This time, we selected PrintLayout, HideOnPrint, and PrintToPDF_Advanced.)

Descriptions of each element are as follows.

PrintLayout: A layout template used to optimize screens for printing or PDF output.

HideOnPrint: A CSS class (style setting) for screen design that, as the name suggests, hides specific elements during printing.

PrintToPDF_Advanced: An advanced function that allows for more detailed settings when converting HTML screens (web pages) into PDFs.

Creating a Screen for Output

To create a screen for output, follow the same steps as when creating a regular Screen. Place ‘PrintLayout’ on the screen and design the layout you want to export as a PDF.

For any text you don’t want to appear in the PDF output, add ‘HideOnPrint’ to the screen and place the text inside it.

Creating a Server Action for PDF Output

This time, we’ll place an output button on the screen we created earlier and set up a Server Action that triggers a download when the button is pressed.

The properties for each action are as follows
・PrintToPDF_Advanced: Under Action, set the URL of the screen you want to export (in this case, we’re using the current screen’s URL), the PDF page size, and the PDF margins.

*We didn’t use it this time, but in Environment, you can finely control HTML rendering methods, wait conditions, and CSS application settings.

・Download: Under Action, set the return value from PrintToPDF_Advanced and the name of the PDF.

Here is the PDF we actually generated.

*Text that wasn’t meant to be output has been removed.

Important Notes

・Be careful when choosing between Client Action and Server Action. Since PDF generation is generally handled on the server side, calling it from a Client Action by mistake may result in it not working properly.

・Always enclose the FileName in double quotation marks (“”).If not specified like \”Test.pdf\”, it will result in an error

・Screens with a large amount of information are more likely to time out. If there are many tables or images, PDF generation may take longer.

Summary

In this article, we introduced how to generate PDF files from OutSystems using Ultimate PDF.
Since it can also output images and graphs, be sure to try it out in apps that generate reports or forms.
Team 2 will continue to share technical blogs using low-code tools like OutSystems, so stay tuned!

技術者ブログ:(OutSystems)Ultimate PDFを使ったPDF出力

技術者ブログとして日ごろ取り組んでいる学習内容をご紹介します。
今回は、ローコード開発をテーマにしているチーム2です。

今回のテーマ:『Ultimate PDFを使ったPDF出力』

今回はOutSystems内にある画面データをPDFとして出力する方法をご紹介します。

Ultimate PDFとは

OutSystemsに搭載されているForgeコンポーネントのひとつで、
Webページ(HTML+CSS)をPDFとして出力できます。
例えば、請求書・報告書・名刺・帳票などレイアウトされた内容をPDF化できます。

Ultimate PDFのインストール

Service Studioを起動しBrowse Forgeより”Ultimate PDF”で検索してインストールを行います。

モジュールへの参照追加

利用したいモジュールを開き、Manage Dependencies(CTRL+Q)よりUltimate PDFの要素を必要な分選択しApplyボタンをクリックします。
(今回はPrintLayout、HideOnPrint、PrintToPDF_Advancedを選択しました)

各要素の説明は以下の通りです。

・PrintLayout …”画面を印刷やPDF出力に最適化するためのレイアウトテンプレート” です。

・HideOnPrint …画面デザインで使えるCSSクラス(スタイル指定)のひとつで、その名の通り「印刷時に非表示にしたい要素」に付けるための機能です。

・PrintToPDF_Advanced …HTML画面(Webページ)をより細かく設定してPDF化できる拡張版の関数です

出力用の画面の作成

出力用の画面を作るときですがScreenを作る時と同じ要領で作成します。
画面に”PrintLayout”を配置しPDF出力したい画面を作成します。

PDF出力する際に出力されてほしくない文字は”HideOnPrint”を画面に追加しその中に文字を入力します。

PDF出力用のSever Actionの作成

今回は上記で作成した画面に出力ボタンを配置し押下時にダウンロードするServerActionを作成します。

各アクションのプロパティは以下の通りです。
・PrintToPDF_Advanced…Action>出力したい画面のURL(今回は現在の画面URLを取得しています)、PDFの画面サイズ、PDFの余白をそれぞれ設定します。

※今回は使っていませんがEnvironmentではHTMLの描画方法・待機条件・CSS適用方法などを細かく制御できます。

・Download…Action>PrintToPDF_Advancedの戻り値、PDFの名前をそれぞれ設定します。

実際に出力したPDFはこちら

※出力したくない文字は消えている

注意事項

・Client Action と Server Action の使い分けに注意。
PDF生成は基本的にサーバー側で行うため、誤って Client Action から呼び出すと正しく動作しない場合があります。

・FileName には必ずダブルクォーテーション(””)を付ける。
"Test.pdf" のように指定しないとエラーになります。

・画面の情報量が多いとタイムアウトしやすい。
テーブルや画像が多いと生成に時間がかかります。

まとめ

今回はUltimate PDFを使ってOutSystemsからPDFファイルを出力する方法をご紹介しました。
画像やグラフなども出力できますので帳票やレポート出力を行うアプリでぜひ活用してみてください。
チーム2ではこれからもOutSystemsなどのローコードツールを使った技術者ブログを展開していきますのでお楽しみに!