# Client

This contains methods and classes providing functionality for interacting with app's client-side and divided into two categories:

* [Client alerts](#client-alerts);
* [Client options](#client-options);

## Client alerts

Classes and methods intended to help in communicating with client side by sending alerts and messages ti be displayed in UI

### ClientAlert

`ClientAlert` class itself represents an alert of specified type with message. This is a main class of alerts infrastructure.

It has two properties:

| Property name | Property type | Description                                          |
| ------------- | ------------- | ---------------------------------------------------- |
| Type          | `string`      | Type of alert. E.g. `Success`, `Warning` or `Error`. |
| Message       | `string`      | Message sending with alert.                          |

### ClientAlertProvider

`ClientAlertProvider` allows to perform alert-related operations, provides methods for assisting in transferring alerts from server side to client.

| Method name        | Return type                | Description                             |
| ------------------ | -------------------------- | --------------------------------------- |
| AddClientAlert     | `void`                     | Adds alert to be transferred to client. |
| GetAllClientAlerts | `IEnumerable<ClientAlert>` | Gets all alerts transferred to client.  |

### Action result

`ClientAlertResult` - represents an alert to be send along with action result.

Extension method for `IActionResult`:

| Method name    | Return type | Description                                |
| -------------- | ----------- | ------------------------------------------ |
| AddClientAlert | `void`      | Appends specified alert to `IActionResult` |

### Sample usage

Create `IActionResult` extensions:

```csharp
public static class ActionResultExtensions
{
    public static IActionResult Info(this IActionResult result, string message)
        => result.AddClientAlert(new JavaScriptAlert("info", message));

    public static IActionResult Success(this IActionResult result, string message)
        => result.AddClientAlert(new JavaScriptAlert("success", message));

    public static IActionResult Warning(this IActionResult result, string message)
        => result.AddClientAlert(new JavaScriptAlert("warning", message));

    public static IActionResult Error(this IActionResult result, string message)
        => result.AddClientAlert(new JavaScriptAlert("error", message));
}
```

Generate `ClientAlert` in server side:

```csharp
public class UsersController : Controller
{
    [HttpPost]
    public async Task<IActionResult> Edit(int id)
    {
        if (ModelState.IsValid)
        {
            /* Some logic here */
            return RedirectToAction(nameof(Index))
                .Success("Successfully edited.");
        }

        return View(editVm);
    }
}
```

Handle alerts in `TagHelper`:

```csharp
[HtmlTargetElement("client-alerts", TagStructure = TagStructure.NormalOrSelfClosing)]
public class ClientAlertsTagHelper : TagHelper
{
    private readonly IClientAlertProvider _alertProvider;

    public ClientAlertsTagHelper(IClientAlertProvider alertProvider)
        => _alertProvider = alertProvider;

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        IEnumerable<ClientAlert> alerts = _alertProvider.GetAllClientAlerts();

        if (alerts.Any() == false)
        {
            output.SuppressOutput();
        }
        else
        {
            output.TagName = "script";
            output.Attributes.SetAttribute("type", "text/javascript");
            output.TagMode = TagMode.StartTagAndEndTag;

            output.Content.AppendHtml(";(function(){");
            foreach (var alert in alerts)
            {
                var type = alert.Type.ToString().ToLower();
                var message = alert.Message.Replace("'", "\'");
                output.Content.AppendHtml($"app.alert('{type}', '{message}');");
            }
            output.Content.AppendHtml("})();");
        }
    }
}
```

Use `ClientAlertsTagHelper` in `_Layout.cshtml` to send `ClientAlert` to client side:

```html
<!DOCTYPE html>
<html>
<head>
    <!-- Some HTML here -->
    <client-alerts/>
</body>
</html>
```

## Client options

This is a group of methods and classes assisting in passing data represented by dictionary via `HttpContext.Items`.

### ClientOptionProvider

It provides methods assisting in passing data represented by dictionary via `HttpContext.Items`:

| Method name           | Return type                                                        | Description                                                                                                                                                                                  |
| --------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AddClientOptions      | `void`                                                             | Places set of options with specified key into current `HttpContext`.                                                                                                                         |
| GetClientOptions      | `IReadOnlyDictionary<string, object>`                              | Gets all options with specified `key` stored in current `HttpContext`.                                                                                                                       |
| GetAllClientOptions   | `IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>>` | Gets all options stored in current `HttpContext`.                                                                                                                                            |
| BuildClientOptionsKey | `string`                                                           | Builds a key for options using `routeData` and taking into account current area, controller and action methods. In such way all options will be related to their corresponding pages (urls). |

### Controller extensions

This controller extensions are helping in manipulating with options:

| Method name      | Return type | Description                                                                                                                                                         |
| ---------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AddClientOptions | `void`      | Adds client options to context associated with controller. There are different versions taking options as object with some public properties or options dictionary. |

### Sample usage

Generate `ClientOption` in server side:

```csharp
public class UsersController
{
    public async Task<IActionResult> Index()
    {
        /* Some logic here */

        this.AddClientOptions(new
        {
            urlEdit = Url.Action(nameof(Edit))
        });

        return View();
    }
}
```

Handle alerts in `TagHelper`:

```csharp
[HtmlTargetElement("client-options", TagStructure = TagStructure.NormalOrSelfClosing)]
public class ClientOptionsTagHelper : TagHelper
{
    private readonly IClientOptionProvider _optionProvider;

    public ClientOptionsTagHelper(IClientOptionProvider optionProvider)
        => _optionProvider = optionProvider;

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        var options = _optionProvider.GetAllClientOptions();

        if (options.Any() == false)
        {
            output.SuppressOutput();
        }
        else
        {
            output.TagName = "script";
            output.Attributes.SetAttribute("type", "text/javascript");
            output.TagMode = TagMode.StartTagAndEndTag;

            var serializer = new JsonSerializer()
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            };

            output.Content.AppendHtml(";(function(){");
            foreach (var option in options)
            {
                var key = option.Key;
                var keyOptions = JObject.FromObject(option.Value, serializer).ToString(Formatting.None);
                output.Content.AppendHtml($"app.options('{key}', {keyOptions});");
            }
            output.Content.AppendHtml("})();");
        }
    }
}
```

Use `ClientOptionsTagHelper` in `_Layout.cshtml` to send `ClientOption` to client side:

```html
<!DOCTYPE html>
<html>
<head>
    <!-- Some HTML here -->
    <client-options/>
</body>
</html>
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.structr.dev/presentation/aspnetcore/client.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
