From 9dbf61a3bfb57aeb10923bffefcea18e911f40b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 8 Oct 2020 20:44:49 +0300 Subject: [PATCH] Documented JavaScript AJAX API for the MVC UI --- docs/en/UI/AspNetCore/JavaScript-API/Ajax.md | 102 ++++++++++++++++++ .../Dynamic-JavaScript-Client-Proxies.md | 3 + .../UI/AspNetCore/JavaScript-API/Message.md | 3 + docs/en/docs-nav.json | 13 +++ docs/en/images/ajax-error.png | Bin 0 -> 15640 bytes 5 files changed, 121 insertions(+) create mode 100644 docs/en/UI/AspNetCore/JavaScript-API/Ajax.md create mode 100644 docs/en/UI/AspNetCore/JavaScript-API/Dynamic-JavaScript-Client-Proxies.md create mode 100644 docs/en/UI/AspNetCore/JavaScript-API/Message.md create mode 100644 docs/en/images/ajax-error.png diff --git a/docs/en/UI/AspNetCore/JavaScript-API/Ajax.md b/docs/en/UI/AspNetCore/JavaScript-API/Ajax.md new file mode 100644 index 0000000000..b06124f252 --- /dev/null +++ b/docs/en/UI/AspNetCore/JavaScript-API/Ajax.md @@ -0,0 +1,102 @@ +# ASP.NET Core MVC / Razor Pages UI JavaScript AJAX API + +`abp.ajax` API provides a convenient way of performing AJAX calls to the server. It internally uses JQuery's `$.ajax`, but automates some common tasks for you; + +* Automatically **handles & localize the errors** and informs the user (using the [abp.message](Message.md)). So you typically don't care about errors. +* Automatically adds **anti forgery** token to the HTTP header to satisfy CSRF protection validation on the server side. +* Automatically sets **default options** and allows to configure the defaults in a single place. +* Can **block** a UI part (or the full page) during the AJAX operation. +* Allows to fully customize any AJAX call, by using the standard `$.ajax` **options**. + +> While `abp.ajax` makes the AJAX call pretty easier, you typically will use the [Dynamic JavaScript Client Proxy](Dynamic-JavaScript-Client-Proxies.md) system to perform calls to your server side HTTP APIs. `abp.ajax` can be used when you need to perform low level AJAX operations. + +## Usage + +`abp.ajax` accepts an options object that is accepted by the standard [$.ajax](https://api.jquery.com/jquery.ajax/#jQuery-ajax-settings). All the standard options are valid. It returns a [promise](https://api.jquery.com/category/deferred-object/) as the return value. + +**Example: Get the list of users** + +````js +abp.ajax({ + type: 'GET', + url: '/api/identity/users' +}).then(function(result){ + console.log(result); +}); +```` + +This command logs the list of users to the console, if you've **logged in** to the application and have [permission](../../../Authorization.md) for the user management page of the [Identity Module](../../../Modules/Identity.md). + +## Error Handling + +The example AJAX call above shows an **error message** if you haven't login to the application or you don't have the necessary permissions to perform this request: + +![ajax-error](D:\Github\abp\docs\en\images\ajax-error.png) + +All kinds of errors are automatically handled by `abp.ajax`, unless you want to disable it. + +### Standard Error Response + +`abp.ajax` is compatible with the [exception handling system](../../../Exception-Handling.md) of the ABP Framework and it properly handles the standard error format returned from the server. A typical error message is a JSON as like below: + +````json +{ + "error": { + "code": "App:010042", + "message": "This topic is locked and can not add a new message", + "details": "A more detailed info about the error..." + } +} +```` + +### Non-Standard Error Response & HTTP Status Codes + +It also handles errors even if the standard error format was not sent by the server. This can be case if you bypass the ABP exception handling system and manually build the HTTP response on the server. In that case, **HTTP status codes** are considered. + +The following HTTP Status Codes are pre-defined; + +* **401**: Shows an error message like "*You should be authenticated (sign in) in order to perform this operation*". When the users click the OK button, they are redirected to the home page of the application to make them login again. +* **403**: Shows an error message like "*You are not allowed to perform this operation*". +* **404**: Shows an error message like "*The resource requested could not found on the server*". +* **Others**: Shows a generic error message like "*An error has occurred. Error detail not sent by server*". + +All these messages are localized based on the current user's language. + +### Manually Handling the Errors + +Since `abp.ajax` returns a promise, you can always chain a `.cactch(...)` call to register a callback that is executed if the AJAX request fails. + +**Example: Show an alert if the AJAX request fails** + +````js +abp.ajax({ + type: 'GET', + url: '/api/identity/users' +}).then(function(result){ + console.log(result); +}).catch(function(){ + alert("request failed :("); +}); +```` + +While your callback is fired, ABP still handles the error itself. If you want to disable automatic error handling, pass `abpHandleError: false` the the `abp.ajax` options. + +**Example: Disable the auto error handling** + +````js +abp.ajax({ + type: 'GET', + url: '/api/identity/users', + abpHandleError: false //DISABLE AUTO ERROR HANDLING +}).then(function(result){ + console.log(result); +}).catch(function(){ + alert("request failed :("); +}); +```` + +If you set `abpHandleError: false` and don't catch the error yourself, then the error will be hidden and the request silently fails. `abp.ajax` still logs the error to the browser console (see the *Configuration* section to override it). + +## Configuration + +TODO \ No newline at end of file diff --git a/docs/en/UI/AspNetCore/JavaScript-API/Dynamic-JavaScript-Client-Proxies.md b/docs/en/UI/AspNetCore/JavaScript-API/Dynamic-JavaScript-Client-Proxies.md new file mode 100644 index 0000000000..5270852b60 --- /dev/null +++ b/docs/en/UI/AspNetCore/JavaScript-API/Dynamic-JavaScript-Client-Proxies.md @@ -0,0 +1,3 @@ +# ASP.NET Core MVC / Razor Pages UI: Dynamic JavaScript Client Proxies + +TODO \ No newline at end of file diff --git a/docs/en/UI/AspNetCore/JavaScript-API/Message.md b/docs/en/UI/AspNetCore/JavaScript-API/Message.md new file mode 100644 index 0000000000..5201e44ca9 --- /dev/null +++ b/docs/en/UI/AspNetCore/JavaScript-API/Message.md @@ -0,0 +1,3 @@ +# ASP.NET Core MVC / Razor Pages UI: JavaScript Message API + +TODO \ No newline at end of file diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index f49414dcb6..45ad58a4d4 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -440,6 +440,19 @@ "text": "Theming", "path": "UI/AspNetCore/Theming.md" }, + { + "text": "JavaScript API", + "items": [ + { + "text": "Overall", + "path": "UI/AspNetCore/JavaScript-API/Index.md" + }, + { + "text": "AJAX", + "path": "UI/AspNetCore/JavaScript-API/Ajax.md" + } + ] + }, { "text": "Customize/Extend the UI", "path": "UI/AspNetCore/Customization-User-Interface.md" diff --git a/docs/en/images/ajax-error.png b/docs/en/images/ajax-error.png new file mode 100644 index 0000000000000000000000000000000000000000..2b9bc2bb37a03b15fc5b65acc0df98aa90c7c65e GIT binary patch literal 15640 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
QlXG|1$tx%>wyd-AB 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