Skip to content

Commit

Permalink
Convert web API jQuery doc to Fetch API (#13874)
Browse files Browse the repository at this point in the history
* Convert web API jQuery doc to Fetch API

* More work

* More edits

* Add missing file extension to source_path

* More edits

* Fix broken section anchor link
  • Loading branch information
scottaddie committed Aug 27, 2019
1 parent becb8c8 commit c566f9f
Show file tree
Hide file tree
Showing 10 changed files with 286 additions and 277 deletions.
5 changes: 5 additions & 0 deletions .openpublishing.redirection.json
Expand Up @@ -879,6 +879,11 @@
"source_path": "aspnetcore/host-and-deploy/azure-apps/troubleshoot.md",
"redirect_url": "/aspnet/core/test/troubleshoot-azure-iis",
"redirect_document_id": false
},
{
"source_path": "aspnetcore/tutorials/web-api-jquery.md",
"redirect_url": "/aspnet/core/tutorials/web-api-javascript",
"redirect_document_id": false
}
]
}
4 changes: 2 additions & 2 deletions aspnetcore/toc.yml
Expand Up @@ -81,9 +81,9 @@
- name: Web API with MongoDB
displayName: tutorial
uid: tutorials/first-mongo-app
- name: Web API with jQuery
- name: Web API with JavaScript
displayName: tutorial
uid: tutorials/web-api-jquery
uid: tutorials/web-api-javascript
- name: Backend for mobile
displayName: tutorial
uid: mobile/native-mobile-backend
Expand Down
22 changes: 10 additions & 12 deletions aspnetcore/tutorials/first-web-api.md
Expand Up @@ -4,7 +4,7 @@ author: rick-anderson
description: Learn how to build a web API with ASP.NET Core.
ms.author: riande
ms.custom: mvc
ms.date: 08/14/2019
ms.date: 08/27/2019
uid: tutorials/first-web-api
---

Expand Down Expand Up @@ -457,9 +457,9 @@ Use Postman to delete a to-do item:
* Set the URI of the object to delete, for example `https://localhost:5001/api/TodoItems/1`
* Select **Send**

## Call the API from jQuery
## Call the web API with JavaScript

See [Tutorial: Call an ASP.NET Core web API with jQuery](xref:tutorials/web-api-jquery).
See [Tutorial: Call an ASP.NET Core web API with JavaScript](xref:tutorials/web-api-javascript).

::: moniker-end

Expand All @@ -475,9 +475,10 @@ In this tutorial, you learn how to:
> * Configure routing and URL paths.
> * Specify return values.
> * Call the web API with Postman.
> * Call the web API with jQuery.
> * Call the web API with JavaScript.
At the end, you have a web API that can manage "to-do" items stored in a relational database.

## Overview

This tutorial creates the following API:
Expand Down Expand Up @@ -732,7 +733,6 @@ The return type of the `GetTodoItems` and `GetTodoItem` methods is [ActionResult
* If no item matches the requested ID, the method returns a 404 [NotFound](/dotnet/api/microsoft.aspnetcore.mvc.controllerbase.notfound) error code.
* Otherwise, the method returns 200 with a JSON response body. Returning `item` results in an HTTP 200 response.


## Test the GetTodoItems method

This tutorial uses Postman to test the web API.
Expand Down Expand Up @@ -858,9 +858,9 @@ Use Postman to delete a to-do item:

The sample app allows you to delete all the items. However, when the last item is deleted, a new one is created by the model class constructor the next time the API is called.

## Call the API with jQuery
## Call the web API with JavaScript

In this section, an HTML page is added that uses jQuery to call the web api. jQuery initiates the request and updates the page with the details from the API's response.
In this section, an HTML page is added that uses JavaScript to call the web API. The Fetch API initiates the request. JavaScript updates the page with the details from the web API's response.

Configure the app to [serve static files](/dotnet/api/microsoft.aspnetcore.builder.staticfileextensions.usestaticfiles#Microsoft_AspNetCore_Builder_StaticFileExtensions_UseStaticFiles_Microsoft_AspNetCore_Builder_IApplicationBuilder_) and [enable default file mapping](/dotnet/api/microsoft.aspnetcore.builder.defaultfilesextensions.usedefaultfiles#Microsoft_AspNetCore_Builder_DefaultFilesExtensions_UseDefaultFiles_Microsoft_AspNetCore_Builder_IApplicationBuilder_) by updating *Startup.cs* with the following highlighted code:

Expand All @@ -881,19 +881,17 @@ A change to the ASP.NET Core project's launch settings may be required to test t
* Open *Properties\launchSettings.json*.
* Remove the `launchUrl` property to force the app to open at *index.html*—the project's default file.

There are several ways to get jQuery. In the preceding snippet, the library is loaded from a CDN.

This sample calls all of the CRUD methods of the API. Following are explanations of the calls to the API.
This sample calls all of the CRUD methods of the web API. Following are explanations of the calls to the API.

### Get a list of to-do items

The jQuery [ajax](https://api.jquery.com/jquery.ajax/) function sends a `GET` request to the API, which returns JSON representing an array of to-do items. The `success` callback function is invoked if the request succeeds. In the callback, the DOM is updated with the to-do information.
Fetch sends an HTTP GET request to the web API, which returns JSON representing an array of to-do items. The `success` callback function is invoked if the request succeeds. In the callback, the DOM is updated with the to-do information.

[!code-javascript[](first-web-api/samples/2.2/TodoApi/wwwroot/site.js?name=snippet_GetData)]

### Add a to-do item

The [ajax](https://api.jquery.com/jquery.ajax/) function sends a `POST` request with the to-do item in the request body. The `accepts` and `contentType` options are set to `application/json` to specify the media type being received and sent. The to-do item is converted to JSON by using [JSON.stringify](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). When the API returns a successful status code, the `getData` function is invoked to update the HTML table.
Fetch sends an HTTP POST request with the to-do item in the request body. The `accepts` and `contentType` options are set to `application/json` to specify the media type being received and sent. The to-do item is converted to JSON by using [JSON.stringify](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). When the API returns a successful status code, the `getData` function is invoked to update the HTML table.

[!code-javascript[](first-web-api/samples/2.2/TodoApi/wwwroot/site.js?name=snippet_AddItem)]

Expand Down
Expand Up @@ -9,9 +9,9 @@

namespace TodoApi
{
public class StartupJquery
public class StartupJavaScript
{
public StartupJquery(IConfiguration configuration)
public StartupJavaScript(IConfiguration configuration)
{
Configuration = configuration;
}
Expand Down
@@ -0,0 +1,23 @@
input[type='submit'], button, [aria-label] {
cursor: pointer;
}

#editForm {
display: none;
}

table {
font-family: Arial, sans-serif;
border: 1px solid;
border-collapse: collapse;
}

th {
background-color: #f8f8f8;
padding: 5px;
}

td {
border: 1px solid;
padding: 5px;
}
Expand Up @@ -3,31 +3,7 @@
<head>
<meta charset="UTF-8">
<title>To-do CRUD</title>
<style>
input[type='submit'], button, [aria-label] {
cursor: pointer;
}

#spoiler {
display: none;
}

table {
font-family: Arial, sans-serif;
border: 1px solid;
border-collapse: collapse;
}

th {
background-color: #0066CC;
color: white;
}

td {
border: 1px solid;
padding: 5px;
}
</style>
<link rel="stylesheet" href="css/site.css" />
</head>
<body>
<h1>To-do CRUD</h1>
Expand All @@ -37,9 +13,9 @@ <h3>Add</h3>
<input type="submit" value="Add">
</form>

<div id="spoiler">
<div id="editForm">
<h3>Edit</h3>
<form class="my-form">
<form action="javascript:void(0);" onsubmit="updateItem()">
<input type="hidden" id="edit-id">
<input type="checkbox" id="edit-isComplete">
<input type="text" id="edit-name">
Expand All @@ -52,17 +28,17 @@ <h3>Edit</h3>

<table>
<tr>
<th>Is Complete</th>
<th>Is Complete?</th>
<th>Name</th>
<th></th>
<th></th>
</tr>
<tbody id="todos"></tbody>
</table>

<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.4.1.js"
integrity="sha384-mlceH9HlqLp7GMKHrj5Ara1+LvdTZVMx4S1U43/NxCvAkzIo8WJ0FE7duLel3wVo"
crossorigin="anonymous"></script>
<script src="site.js"></script>
<script src="js/site.js" asp-append-version="true"></script>
<script type="text/javascript">
getItems();
</script>
</body>
</html>
@@ -0,0 +1,135 @@
// <snippet_SiteJs>
const uri = 'api/TodoItems';
let todos = [];

function getItems() {
// <snippet_GetItems>
fetch(uri)
.then(response => response.json())
.then(data => _displayItems(data))
.catch(error => console.error('Unable to get items.', error));
// </snippet_GetItems>
}

// <snippet_AddItem>
function addItem() {
const addNameTextbox = document.getElementById('add-name');

const item = {
isComplete: false,
name: addNameTextbox.value.trim()
};

fetch(uri, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(item)
})
.then(response => response.json())
.then(() => {
getItems();
addNameTextbox.value = '';
})
.catch(error => console.error('Unable to add item.', error));
}
// </snippet_AddItem>

function deleteItem(id) {
// <snippet_DeleteItem>
fetch(`${uri}/${id}`, {
method: 'DELETE'
})
.then(() => getItems())
.catch(error => console.error('Unable to delete item.', error));
// </snippet_DeleteItem>
}

function displayEditForm(id) {
const item = todos.find(item => item.id === id);

document.getElementById('edit-name').value = item.name;
document.getElementById('edit-id').value = item.id;
document.getElementById('edit-isComplete').checked = item.isComplete;
document.getElementById('editForm').style.display = 'block';
}

function updateItem() {
const itemId = document.getElementById('edit-id').value;
const item = {
id: parseInt(itemId, 10),
isComplete: document.getElementById('edit-isComplete').checked,
name: document.getElementById('edit-name').value.trim()
};

// <snippet_UpdateItem>
fetch(`${uri}/${itemId}`, {
method: 'PUT',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(item)
})
.then(() => getItems())
.catch(error => console.error('Unable to delete item.', error));
// </snippet_UpdateItem>

closeInput();

return false;
}

function closeInput() {
document.getElementById('editForm').style.display = 'none';
}

function _displayCount(itemCount) {
const name = (itemCount === 1) ? 'to-do' : 'to-dos';

document.getElementById('counter').innerText = `${itemCount} ${name}`;
}

function _displayItems(data) {
const tBody = document.getElementById('todos');
tBody.innerHTML = '';

_displayCount(data.length);

const button = document.createElement('button');

data.forEach(item => {
let isCompleteCheckbox = document.createElement('input');
isCompleteCheckbox.type = 'checkbox';
isCompleteCheckbox.disabled = true;
isCompleteCheckbox.checked = item.isComplete;

let editButton = button.cloneNode(false);
editButton.innerText = 'Edit';
editButton.setAttribute('onclick', `displayEditForm(${item.id})`);

let deleteButton = button.cloneNode(false);
deleteButton.innerText = 'Delete';
deleteButton.setAttribute('onclick', `deleteItem(${item.id})`);

let tr = tBody.insertRow();

let td1 = tr.insertCell(0);
td1.appendChild(isCompleteCheckbox);

let td2 = tr.insertCell(1);
let textNode = document.createTextNode(item.name);
td2.appendChild(textNode);

let td3 = tr.insertCell(2);
td3.appendChild(editButton);

let td4 = tr.insertCell(3);
td4.appendChild(deleteButton);
});

todos = data;
}
// </snippet_SiteJs>

0 comments on commit c566f9f

Please sign in to comment.