mirror of
https://github.com/m-lamonaca/dev-notes.git
synced 2025-06-08 10:47:13 +00:00
Rename all file to kebab-case
This commit is contained in:
parent
ffc085d78a
commit
68ca4e4f86
117 changed files with 0 additions and 1260 deletions
112
javascript/ajax.md
Normal file
112
javascript/ajax.md
Normal file
|
@ -0,0 +1,112 @@
|
|||
# AJAX
|
||||
|
||||
**AJAX**: Asynchronous JavaScript and XML
|
||||
|
||||
AJAX Interaction:
|
||||
|
||||
1. An event occurs in a web page (the page is loaded, a button is clicked)
|
||||
2. 2.An `XMLHttpRequest` object is created by JavaScript
|
||||
3. 3.The `XMLHttpRequest` object sends a request to a web server
|
||||
4. 4.The server processes the request
|
||||
5. 5.The server sends a response back to the web page
|
||||
6. 6.The response is read by JavaScript
|
||||
7. 7.Proper action (like page update) is performed by JavaScript
|
||||
|
||||
## XMLHttpRequest
|
||||
|
||||
```js
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
request.addEventListener(event, function() {...});
|
||||
|
||||
request.open("HttpMethod", "path/to/api", true); // third parameter is asynchronicity (true = asynchronous)
|
||||
request.setRequestHeader(key, value) // HTTP Request Headers
|
||||
request.send()
|
||||
```
|
||||
|
||||
To check the status use `XMLHttpRequest.status` and `XMLHttpRequest.statusText`.
|
||||
|
||||
### XMLHttpRequest Events
|
||||
|
||||
**loadstart**: fires when the process of loading data has begun. This event always fires first
|
||||
**progress**: fires multiple times as data is being loaded, giving access to intermediate data
|
||||
**error**: fires when loading has failed
|
||||
**abort**: fires when data loading has been canceled by calling abort()
|
||||
**load**: fires only when all data has been successfully read
|
||||
**loadend**: fires when the object has finished transferring data always fires and will always fire after error, abort, or load
|
||||
**timeout**: fires when progression is terminated due to preset time expiring
|
||||
**readystatechange**: fires when the readyState attribute of a document has changed
|
||||
|
||||
**Alternative `XMLHttpRequest` using `onLoad`**:
|
||||
|
||||
```js
|
||||
var request = new XMLHttpRequest();
|
||||
request.open('GET', 'myservice/username?id=some-unique-id');
|
||||
request.onload = function(){
|
||||
if(request.status ===200){
|
||||
console.log("User's name is "+ request.responseText);
|
||||
} else {
|
||||
console.log('Request failed. Returned status of '+ request.status);
|
||||
}
|
||||
};
|
||||
request.send();
|
||||
```
|
||||
|
||||
**Alternative `XMLHttpRequest` using `readyState`**:
|
||||
|
||||
```js
|
||||
var request = new XMLHttpRequest(), method ='GET', url ='https://developer.mozilla.org/';
|
||||
|
||||
request.open(method, url, true);
|
||||
request.onreadystatechange = function(){
|
||||
if(request.readyState === XMLHttpRequest.DONE && request.status === 200){
|
||||
console.log(request.responseText);
|
||||
}
|
||||
};
|
||||
request.send();
|
||||
```
|
||||
|
||||
`XMLHttpRequest.readyState` values:
|
||||
`0` `UNSENT`: Client has been created. `open()` not called yet.
|
||||
`1` `OPENED`: `open()` has been called.
|
||||
`2` `HEADERS_RECEIVED`: `send()` has been called, and headers and status are available.
|
||||
`3` `LOADING`: Downloading; `responseText` holds partial data.
|
||||
`4` `DONE`: The operation is complete.
|
||||
|
||||
### `XMLHttpRequest` Browser compatibility
|
||||
|
||||
Old versions of IE don't implement XMLHttpRequest. You must use the ActiveXObject if XMLHttpRequest is not available
|
||||
|
||||
```js
|
||||
var request =window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
|
||||
|
||||
// OR
|
||||
|
||||
var request;
|
||||
if(window.XMLHttpRequest){
|
||||
// code for modern browsers
|
||||
request = new XMLHttpRequest();
|
||||
} else {
|
||||
// code for old IE browsers
|
||||
request = new ActiveXObject('Microsoft.XMLHTTP');
|
||||
}
|
||||
```
|
||||
|
||||
## Status & Error Handling
|
||||
|
||||
Always inform the user when something is loading. Check the status and give feedback (a loader or message)
|
||||
Errors and responses need to be handled. There is no guarantee that HTTP requests will always succeed.
|
||||
|
||||
### Cross Domain Policy
|
||||
|
||||
Cross domain requests have restrictions.
|
||||
|
||||
Examples of outcome for requests originating from: `http://store.company.com/dir/page.htmlCross-origin`
|
||||
|
||||
| URL | Outcome | Reason |
|
||||
|-------------------------------------------------|---------|--------------------|
|
||||
| `http://store.company.com/dir2/other.html` | success |
|
||||
| `http://store.company.com/dir/inner/other.html` | success |
|
||||
| `https://store.company.com/secure.html` | failure | Different protocol |
|
||||
| `http://store.company.com:81/dir/other.html` | failure | Different port |
|
||||
| `http://news.company.com/dir/other.html` | failure | Different host |
|
164
javascript/dom.md
Normal file
164
javascript/dom.md
Normal file
|
@ -0,0 +1,164 @@
|
|||
# Document Object Model (DOM)
|
||||
|
||||
The **Document Object Model** is a *map* of the HTML document. Elements in an HTML document can be accessed, changed, deleted, or added using the DOM.
|
||||
The document object is *globally available* in the browser. It allows to access and manipulate the DOM of the current web page.
|
||||
|
||||
## DOM Access
|
||||
|
||||
### Selecting Nodes from the DOM
|
||||
|
||||
`getElementById()` and `querySelector()` return a single element.
|
||||
`getElementsByClassName()`, `getElementsByTagName()`, and `querySelectorAll()` return a collection of elements.
|
||||
|
||||
```js
|
||||
Javascript
|
||||
// By Id
|
||||
var node = document.getElementById('id');
|
||||
|
||||
// By Tag Name
|
||||
var nodes = document.getElementsByTagName('tag');
|
||||
|
||||
// By Class Name
|
||||
var nodes = document.getElementsByClassName('class');
|
||||
|
||||
// By CSS Query
|
||||
var node = document.querySelector('css-selector');
|
||||
var nodes = document.querySelectorAll('css-selector');
|
||||
```
|
||||
|
||||
## Manipulating the DOM
|
||||
|
||||
### Manipulating a node's attributes
|
||||
|
||||
It's possible access and change the attributes of a DOM node using the *dot notation*.
|
||||
|
||||
```js
|
||||
// Changing the src of an image:
|
||||
var image = document.getElementById('id');
|
||||
var oldImageSource = image.src;
|
||||
image.src = 'image-url';
|
||||
|
||||
//Changing the className of a DOM node:
|
||||
var node = document.getElementById('id');
|
||||
node.className = 'new-class';
|
||||
```
|
||||
|
||||
### Manipulating a node's style
|
||||
|
||||
It's possible to access and change the styles of a DOM nodes via the **style** property.
|
||||
CSS property names with a `-` must be **camelCased** and number properties must have a unit.
|
||||
|
||||
```css
|
||||
body {
|
||||
color: red;
|
||||
background-color: pink;
|
||||
padding-top: 10px;
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
var pageNode = document.body;
|
||||
pageNode.style.color = 'red';
|
||||
pageNode.style.backgroundColor = 'pink';
|
||||
pageNode.style.paddingTop = '10px';
|
||||
```
|
||||
|
||||
### Manipulating a node's contents
|
||||
|
||||
Each DOM node has an `innerHTML` attribute. It contains the HTML of all its children.
|
||||
|
||||
```js
|
||||
var pageNode = document.body;
|
||||
console.log(pageNode.innerHTML);
|
||||
|
||||
// Set innerHTML to replace the contents of the node:
|
||||
pageNode.innerHTML = "<h1>Oh, no! Everything is gone!</h1>";
|
||||
|
||||
// Or add to innerHTML instead:
|
||||
pageNode.innerHTML += "P.S. Please do write back.";
|
||||
```
|
||||
|
||||
To change the actual text of a node, `textContent` may be a better choice:
|
||||
|
||||
`innerHTML`:
|
||||
|
||||
- Works in older browsers
|
||||
- **More powerful**: can change code
|
||||
- **Less secure**: allows cross-site scripting (XSS)
|
||||
|
||||
`textContent`:
|
||||
|
||||
- Doesn't work in IE8 and below
|
||||
- **Faster**: the browser doesn't have to parse HTML
|
||||
- **More secure**: won't execute code
|
||||
|
||||
### Reading Inputs From A Form
|
||||
|
||||
In `page.html`:
|
||||
|
||||
```html
|
||||
<input type="" id="identifier" value="">
|
||||
```
|
||||
|
||||
In `script.js`:
|
||||
|
||||
```js
|
||||
var formNode = document.getElementById("Identifier");
|
||||
var value = formNode.value;
|
||||
```
|
||||
|
||||
## Creating & Removing DOM Nodes
|
||||
|
||||
The document object also allows to create new nodes from scratch.
|
||||
|
||||
```js
|
||||
// create node
|
||||
document.createElement('tagName');
|
||||
document.createTextNode('text');
|
||||
|
||||
domNode.appendChild(childToAppend); // insert childTaAppend after domNode
|
||||
|
||||
// insert node before domNode
|
||||
domNode.insertBefore(childToInsert, domnode);
|
||||
domNode.parentNode.insertBefore(childToInsert, nodeAfterChild);
|
||||
|
||||
// remove a node
|
||||
domNode.removeChild(childToRemove);
|
||||
node.parentNode.removeChild(node);
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
var body = document.body;
|
||||
|
||||
var newImg = document.createElement('img');
|
||||
newImg.src = 'http://placekitten.com/400/300';
|
||||
newImg.style.border = '1px solid black';
|
||||
|
||||
body.appendChild(newImg);
|
||||
|
||||
var newParagraph = document.createElement('p');
|
||||
var newText = document.createTextNode('Squee!');
|
||||
|
||||
newParagraph.appendChild(newText);
|
||||
|
||||
body.appendChild(newParagraph);
|
||||
```
|
||||
|
||||
### Creating DOM Nodes with Constructor Functions
|
||||
|
||||
```js
|
||||
function Node(params) {
|
||||
this.node = document.createElement("tag");
|
||||
|
||||
this.node.attribute = value;
|
||||
|
||||
// operations on the node
|
||||
|
||||
return this.node;
|
||||
}
|
||||
|
||||
var node = Node(params);
|
||||
domElement.appendChild(node);
|
||||
```
|
88
javascript/events-animation.md
Normal file
88
javascript/events-animation.md
Normal file
|
@ -0,0 +1,88 @@
|
|||
# Events & Animation
|
||||
|
||||
## Events
|
||||
|
||||
Event Types:
|
||||
|
||||
- **Mouse Events**: `mousedown`, `mouseup`, `click`, `dbclick`, `mousemove`, `mouseover`, `mousewheel`, `mouseout`, `contextmenu`, ...
|
||||
- **Touch Events**: `touchstart`, `touchmove`, `touchend`, `touchcancel`, ...
|
||||
- **Keyboard Events**: `keydown`, `keypress`, `keyup`, ...
|
||||
- **Form Events**: `focus`, `blur`, `change`, `submit`, ...
|
||||
- **Window Events**: `scroll`, `resize`, `hashchange`, `load`, `unload`, ...
|
||||
|
||||
### Managing Event Listeners
|
||||
|
||||
```js
|
||||
var domNode = document.getElementById("id");
|
||||
|
||||
var onEvent = function(event) { // parameter contains info on the triggered event
|
||||
event.preventDefault(); // block execution of default action
|
||||
// logic here
|
||||
}
|
||||
|
||||
domNode.addEventListener(eventType, callback);
|
||||
domNode.removeEventListener(eventType, callback);
|
||||
```
|
||||
|
||||
### Bubbling & Capturing
|
||||
|
||||
Events in Javascript propagate through the DOM tree.
|
||||
|
||||
[Bubbling and Capturing](https://javascript.info/bubbling-and-capturing)
|
||||
[What Is Event Bubbling in JavaScript? Event Propagation Explained](https://www.sitepoint.com/event-bubbling-javascript/)
|
||||
|
||||
### Dispatching Custom Events
|
||||
|
||||
Event Options:
|
||||
|
||||
- `bubbles` (bool): whether the event propagates through bubbling
|
||||
- `cancellable` (bool): if `true` the "default action" may be prevented
|
||||
|
||||
```js
|
||||
let event = new Event(type [,options]); // create the event, type can be custom
|
||||
let event = new CustomEvent(type, { detail: /* custom data */ }); // create event w/ custom data
|
||||
domNode.dispatchEvent(event); // launch the event
|
||||
```
|
||||
|
||||

|
||||
|
||||
## Animation
|
||||
|
||||
The window object is the assumed global object on a page.
|
||||
|
||||
Animation in JavascriptThe standard way to animate in JS is to use window methods.
|
||||
It's possible to animate CSS styles to change size, transparency, position, color, etc.
|
||||
|
||||
```js
|
||||
//Calls a function once after a delay
|
||||
window.setTimeout(callbackFunction, delayMilliseconds);
|
||||
|
||||
//Calls a function repeatedly, with specified interval between each call
|
||||
window.setInterval(callbackFunction, delayMilliseconds);
|
||||
|
||||
//To stop an animation store the timer into a variable and clear it
|
||||
window.clearTimeout(timer);
|
||||
window.clearInterval(timer);
|
||||
|
||||
// execute a callback at each frame
|
||||
window.requestAnimationFrame(callbackFunction);
|
||||
```
|
||||
|
||||
### Element Position & dimensions
|
||||
|
||||
[StackOverflow](https://stackoverflow.com/a/294273/8319610)
|
||||
[Wrong dimensions at runtime](https://stackoverflow.com/a/46772849/8319610)
|
||||
|
||||
```js
|
||||
> console.log(document.getElementById('id').getBoundingClientRect());
|
||||
DOMRect {
|
||||
bottom: 177,
|
||||
height: 54.7,
|
||||
left: 278.5,
|
||||
right: 909.5,
|
||||
top: 122.3,
|
||||
width: 631,
|
||||
x: 278.5,
|
||||
y: 122.3,
|
||||
}
|
||||
```
|
958
javascript/javascript.md
Normal file
958
javascript/javascript.md
Normal file
|
@ -0,0 +1,958 @@
|
|||
# JavaScript Cheat Sheet
|
||||
|
||||
## Basics
|
||||
|
||||
### Notable javascript engines
|
||||
|
||||
- **Chromium**: `V8` from Google
|
||||
- **Firefox**: `SpiderMonkey` from Mozilla
|
||||
- **Safari**: `JavaScriptCore` from Apple
|
||||
- **Internet Explorer**: `Chakra` from Microsoft
|
||||
|
||||
### Comments
|
||||
|
||||
```javascript
|
||||
//single line comment
|
||||
/*multiline comment*/
|
||||
```
|
||||
|
||||
### File Header
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @file filename.js
|
||||
* @author author's name
|
||||
* purpose of file
|
||||
*
|
||||
* detailed explanation of what the file does on multiple lines
|
||||
*/
|
||||
```
|
||||
|
||||
### Modern Mode
|
||||
|
||||
If located at the top of the script the whole script works the “modern” way (enables post-ES5 functionalities).
|
||||
|
||||
```js
|
||||
"use strict"
|
||||
|
||||
// script contents
|
||||
```
|
||||
|
||||
### Pop-Up message
|
||||
|
||||
Interrupts script execution until closure, **to be avoided**
|
||||
|
||||
```javascript
|
||||
alert("message");
|
||||
```
|
||||
|
||||
### Print message to console
|
||||
|
||||
`console.log(value);`
|
||||
|
||||
## Variables
|
||||
|
||||
### Declaration & Initialization
|
||||
|
||||
[var vs let vs const](https://www.freecodecamp.org/news/var-let-and-const-whats-the-difference/)
|
||||
|
||||
Variable names can only contain numbers, digits, underscores and $. Variable names are camelCase.
|
||||
|
||||
`let`: Block-scoped; access to variable restricted to the nearest enclosing block.
|
||||
`var`: Function-scoped
|
||||
|
||||
`let variable1 = value1, variable2 = value2;`
|
||||
`var variable1 = value1, variable2 = value2;`
|
||||
|
||||
### Scope
|
||||
|
||||
Variable declared with `let` are in local to the code block in which are declared.
|
||||
Variable declared with `var` are local only if declared in a function.
|
||||
|
||||
```js
|
||||
function func(){
|
||||
variable = value; // implicitly declared as a global variable
|
||||
var variable = value; // local variable
|
||||
}
|
||||
|
||||
var a = 10; // a is 10
|
||||
let b = 10; // b is 10
|
||||
{
|
||||
var x = 2, a = 2; // a is 2
|
||||
let y = 2, b = 2; // b is 2
|
||||
}
|
||||
// a is 2, b is 10
|
||||
// x can NOT be used here
|
||||
// y CAN be used here
|
||||
```
|
||||
|
||||
### Constants
|
||||
|
||||
Hard-coded values are UPPERCASE and snake_case, camelCase otherwise.
|
||||
`const CONSTANT = value;`
|
||||
|
||||
## Data Types
|
||||
|
||||
`Number`, `String`, `Boolean`, etc are *built-in global objects*. They are **not** types. **Do not use them for type checking**.
|
||||
|
||||
### Numeric data types
|
||||
|
||||
Only numeric type is `number`.
|
||||
|
||||
```javascript
|
||||
let number = 10; //integer numbers
|
||||
number = 15.7; //floating point numbers
|
||||
number = Infinity; //mathematical infinity
|
||||
number = - Infinity;
|
||||
number = 1234567890123456789012345678901234567890n; //BigInt, value > 2^53, "n" at the end
|
||||
number = "text" / 2; //NaN --> not a number.
|
||||
```
|
||||
|
||||
[Rounding Decimals in JavaScript](https://www.jacklmoore.com/notes/rounding-in-javascript/)
|
||||
[Decimal.js](https://github.com/MikeMcl/decimal.js)
|
||||
|
||||
Mathematical expression will *never* cause an error. At worst the result will be NaN.
|
||||
|
||||
### String data type
|
||||
|
||||
```javascript
|
||||
let string = "text";
|
||||
let string$ = 'text';
|
||||
let string_ = `text ${expression}`; //string interpolation (needs backticks)
|
||||
|
||||
string.length; // length of the string
|
||||
let char = string.charAt(index); // extraction of a single character by position
|
||||
string[index]; // char extraction by property access
|
||||
let index = string.indexOf(substring); // start index of substring in string
|
||||
```
|
||||
|
||||
Property access is unpredictable:
|
||||
|
||||
- does not work in IE7 or earlier
|
||||
- makes strings look like arrays (confusing)
|
||||
- if no character is found, `[ ]` returns undefined, `charAt()` returns an empty string
|
||||
- Is read only: `string[index] = "value"` does not work and gives no errors
|
||||
|
||||
### [Slice vs Substring vs Substr](https://stackoverflow.com/questions/2243824/what-is-the-difference-between-string-slice-and-string-substring)
|
||||
|
||||
If the parameters to slice are negative, they reference the string from the end. Substring and substr doesn´t.
|
||||
|
||||
```js
|
||||
string.slice(begin [, end]);
|
||||
string.substring(from [, to]);
|
||||
string.substr(start [, length]);
|
||||
```
|
||||
|
||||
### Boolean data type
|
||||
|
||||
```javascript
|
||||
let boolean = true;
|
||||
let boolean_ = false;
|
||||
```
|
||||
|
||||
### Null data type
|
||||
|
||||
```javascript
|
||||
let _ = null;
|
||||
```
|
||||
|
||||
### Undefined
|
||||
|
||||
```javascript
|
||||
let $; //value is "undefined"
|
||||
$ = undefined;
|
||||
```
|
||||
|
||||
### Typeof()
|
||||
|
||||
```javascript
|
||||
typeof x; //returns the type of the variable x as a string
|
||||
typeof(x); //returns the type of the variable x as a string
|
||||
```
|
||||
|
||||
The result of typeof null is "object". That's wrong.
|
||||
It is an officially recognized error in typeof, kept for compatibility. Of course, null is not an object.
|
||||
It is a special value with a separate type of its own. So, again, this is an error in the language.
|
||||
|
||||
### Type Casting
|
||||
|
||||
```javascript
|
||||
String(value); //converts value to string
|
||||
|
||||
Number(value); //converts value to a number
|
||||
Number(undefined); //--> NaN
|
||||
Number(null); //--> 0
|
||||
Number(true); //--> 1
|
||||
Number(false); //--> 0
|
||||
Number(String); //Whitespace from the start and end is removed. If the remaining string is empty, the result is 0. Otherwise, the number is "read" from the string. An error gives NaN.
|
||||
|
||||
Boolean(value); //--> true
|
||||
Boolean(0); //--> false
|
||||
Boolean(""); //--> false
|
||||
Boolean(null); //--> false
|
||||
Boolean(undefined); //--> false
|
||||
Boolean(NaN); //--> false
|
||||
|
||||
|
||||
//numeric type checking the moronic way
|
||||
typeof var_ == "number"; // typeof returns a string with the name of the type
|
||||
```
|
||||
|
||||
### Type Checking
|
||||
|
||||
```js
|
||||
isNaN(var); // converts var in number and then check if is NaN
|
||||
|
||||
Number("A") == NaN; //false ?!?
|
||||
|
||||
```
|
||||
|
||||
### Dangerous & Stupid Implicit Type Casting
|
||||
|
||||
```js
|
||||
2 + 'text'; //"2text", implicit conversion and concatenation
|
||||
1 + "1"; //"11", implicit conversion and concatenation
|
||||
"1" + 1; //"11", implicit conversion and concatenation
|
||||
+"1"; //1, implicit conversion
|
||||
+"text"; // NaN
|
||||
1 == "1"; //true
|
||||
1 === "1"; //false
|
||||
1 == true; //true
|
||||
0 == false; //true
|
||||
"" == false; //true
|
||||
```
|
||||
|
||||
## Operators
|
||||
|
||||
| Operator | Operation |
|
||||
| ------------ | --------------- |
|
||||
| `(...)` | grouping |
|
||||
| a`.`b | member access |
|
||||
| `new` a(...) | object creation |
|
||||
| a `in` b | membership |
|
||||
|
||||
### Mathematical Operators
|
||||
|
||||
| Operator | Operation |
|
||||
| -------- | -------------- |
|
||||
| a `+` b | addition |
|
||||
| a `-` b | subtraction |
|
||||
| a `*` b | multiplication |
|
||||
| a `**` b | a^b |
|
||||
| a `/` b | division |
|
||||
| a `%` b | modulus |
|
||||
|
||||
### Unary Increment Operators
|
||||
|
||||
| Operator | Operation |
|
||||
| ------------ | ----------------- |
|
||||
| `--`variable | prefix decrement |
|
||||
| `++`variable | prefix increment |
|
||||
| variable`--` | postfix decrement |
|
||||
| variable`++` | postfix increment |
|
||||
|
||||
### Logical Operators
|
||||
|
||||
| Operator | Operation |
|
||||
| -------- | --------------- |
|
||||
| a `&&` b | logical **AND** |
|
||||
| a `||` b | logical **OR** |
|
||||
| `!`a | logical **NOT** |
|
||||
|
||||
### Comparison Operators
|
||||
|
||||
| Operator | Operation |
|
||||
| --------- | ------------------- |
|
||||
| a `<` b | less than |
|
||||
| a `<=` b | less or equal to |
|
||||
| a `>` b | greater than |
|
||||
| a `>=` b | greater or equal to |
|
||||
| a `==` b | equality |
|
||||
| a `!=` b | inequality |
|
||||
| a `===` b | strict equality |
|
||||
| a `!==` b | strict inequality |
|
||||
|
||||
### Bitwise Logical Operators
|
||||
|
||||
| Operator | Operation |
|
||||
| --------- | ---------------------------- |
|
||||
| a `&` b | bitwise AND |
|
||||
| a `|` b | bitwise OR |
|
||||
| a `^` b | bitwise XOR |
|
||||
| `~`a | bitwise NOT |
|
||||
| a `<<` b | bitwise left shift |
|
||||
| a `>>` b | bitwise right shift |
|
||||
| a `>>>` b | bitwise unsigned right shift |
|
||||
|
||||
### Compound Operators
|
||||
|
||||
| Operator | Operation |
|
||||
| ---------- | ----------- |
|
||||
| a `+=` b | a = a + b |
|
||||
| a `-=` b | a = a - b |
|
||||
| a `*=` b | a = a * b |
|
||||
| a `**=` b | a = a ** b |
|
||||
| a `/=` b | a = a / b |
|
||||
| a `%=` b | a = a % b |
|
||||
| a `<<=` b | a = a << b |
|
||||
| a `>>=` b | a = a >> b |
|
||||
| a `>>>=` b | a = a >>> b |
|
||||
| a `&=` b | a = a & b |
|
||||
| a `^=` b | a = a ^ b |
|
||||
| a `|=` b | a = a ! b |
|
||||
|
||||
## Decision Statements
|
||||
|
||||
### IF-ELSE
|
||||
|
||||
```javascript
|
||||
if (condition) {
|
||||
//code here
|
||||
} else {
|
||||
//code here
|
||||
}
|
||||
```
|
||||
|
||||
### IF-ELSE Multi-Branch
|
||||
|
||||
```javascript
|
||||
if (condition) {
|
||||
//code here
|
||||
} else if (condition) {
|
||||
//code here
|
||||
} else {
|
||||
//code here
|
||||
}
|
||||
```
|
||||
|
||||
### Ternary Operator
|
||||
|
||||
`condition ? <expr1> : <expr2>;`
|
||||
|
||||
### Switch Statement
|
||||
|
||||
```javascript
|
||||
switch (expression) {
|
||||
case expression:
|
||||
//code here
|
||||
break;
|
||||
|
||||
default:
|
||||
//code here
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
## Loops
|
||||
|
||||
### While Loop
|
||||
|
||||
```javascript
|
||||
while (condition) {
|
||||
//code here
|
||||
}
|
||||
```
|
||||
|
||||
### Do-While Loop
|
||||
|
||||
```javascript
|
||||
do {
|
||||
//code here
|
||||
} while (condition);
|
||||
```
|
||||
|
||||
### For Loop
|
||||
|
||||
```javascript
|
||||
// basic for
|
||||
for (begin; condition; step) { }
|
||||
|
||||
for (var variable in iterable) { } // for/in statement loops through the properties of an object
|
||||
for (let variable in iterable) { } // instantiate a new variable at each iteration
|
||||
|
||||
// for/of statement loops through the values of an iterable objects
|
||||
// for/of lets you loop over data structures that are iterable such as Arrays, Strings, Maps, NodeLists, and more.
|
||||
for (var variable of iterable) { }
|
||||
for (let variable of iterable) { } // instantiate a new variable at each iteration
|
||||
|
||||
// foreach (similar to for..of)
|
||||
iterable.forEach(() => { /* statements */ });
|
||||
```
|
||||
|
||||
### Break & Continue statements
|
||||
|
||||
`break;` exits the loop.
|
||||
`continue;` skip to next loop cycle.
|
||||
|
||||
```javascript
|
||||
label: for(begin; condition; step) {
|
||||
//code here
|
||||
}
|
||||
|
||||
break label; //breaks labelled loop and nested loops inside it
|
||||
```
|
||||
|
||||
## Arrays
|
||||
|
||||
```js
|
||||
let array = []; // empty array
|
||||
let array = ["text", 3.14, [1.41]]; // array declaration and initialization
|
||||
|
||||
array.length; // number of items in the array
|
||||
array[index]; // access to item by index
|
||||
array[index] = item; // change or add item by index
|
||||
|
||||
array.push(item); //add item to array
|
||||
array.pop(); // remove and return last item
|
||||
|
||||
array.join("separator"); // construct a string from the items of the array, separated by SEPARATOR
|
||||
array.find(item => condition); // returns the value of the first element in the provided array that satisfies the provided testing function
|
||||
array.fill(value, start, end); // fills an array with the passed value
|
||||
|
||||
|
||||
// https://stackoverflow.com/a/37601776
|
||||
array.slice(start, end); // RETURN list of items between indexes start and end-1
|
||||
array.splice(start, deleteCount, [items_to_add]); // remove and RETURN items from array, can append a list of items. IN PLACE operation
|
||||
```
|
||||
|
||||
### `filter()` & `map()`, `reduce()`
|
||||
|
||||
```js
|
||||
let array = [ items ];
|
||||
|
||||
// execute an operation on each item, producing a new array
|
||||
array.map(function);
|
||||
array.map(() => operation);
|
||||
|
||||
array.filter(() => condition); // return an items only if the condition is true
|
||||
|
||||
// execute a reducer function on each element of the array, resulting in single output value
|
||||
array.reduce((x, y) => ...);
|
||||
```
|
||||
|
||||
## Spread Operator (...)
|
||||
|
||||
```js
|
||||
// arrays
|
||||
let array1 = [ 1, 2, 3, 4, 5, 6 ];
|
||||
let array2 = [ 7, 8, 9, 10 ];
|
||||
let copy = [ ...array1 ]; // shallow copy
|
||||
let copyAndAdd = [ 0, ...array1, 7 ]; // insert all values in new array
|
||||
let merge = [ ...array1, ...array2 ]; // merge the arrays contents in new array
|
||||
|
||||
// objects
|
||||
let obj = { prop1: value1, prop2: value2 };
|
||||
let clone = { ...obj, prop: value }; // shallow copy, and update copy prop
|
||||
let cloneAndAdd = { prop0: value0, ...obj, prop3: value3 };
|
||||
|
||||
// strings
|
||||
let alphabet = "abcdefghijklmnopqrstxyz"
|
||||
let letters = [ ...alphabet ]; // alphabet.split("")
|
||||
|
||||
//function arguments
|
||||
let func = (arg1 = val1, arg2 = val2) => expression;
|
||||
let args = [ value1, value2 ];
|
||||
func(arg0, ...args);
|
||||
```
|
||||
|
||||
## Dictionaries
|
||||
|
||||
```js
|
||||
let dict = { FirstName: "Chris", "one": 1, 1: "some value" };
|
||||
|
||||
|
||||
// add new or update property
|
||||
dict["Age"] = 42;
|
||||
|
||||
// direct property by name
|
||||
// because it's a dynamic language
|
||||
dict.FirstName = "Chris";
|
||||
```
|
||||
|
||||
### Iterating Key-Value pairs
|
||||
|
||||
```js
|
||||
for(let key in dict) {
|
||||
let value = dict[key];
|
||||
|
||||
// do something with "key" and "value" variables
|
||||
}
|
||||
|
||||
Object.keys(dict).forEach(key => { });
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
### JSDOC documentation standard
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @param {type} parameter - description
|
||||
* @returns {type} parameter - description
|
||||
* */
|
||||
```
|
||||
|
||||
### Function Declaration
|
||||
|
||||
```javascript
|
||||
// ...args will contain extra parameters (rest argument)
|
||||
function functionName(parameter=default-value, ...args) {
|
||||
//code here
|
||||
return <expression>;
|
||||
}
|
||||
```
|
||||
|
||||
### Default Parameters (old versions)
|
||||
|
||||
```javascript
|
||||
function functionName(parameters) {
|
||||
if (parameter == undefined) {
|
||||
parameter = value;
|
||||
}
|
||||
|
||||
//code here
|
||||
return <expression>;
|
||||
}
|
||||
```
|
||||
|
||||
### Function Expressions
|
||||
|
||||
```javascript
|
||||
let functionName = function(parameters) {
|
||||
//code here
|
||||
return expression;
|
||||
}
|
||||
```
|
||||
|
||||
### Arrow Functions
|
||||
|
||||
```javascript
|
||||
(input) => { /* statements */ }
|
||||
(input) => expression;
|
||||
input => expression; // parenthesis are optional
|
||||
() => expression; // no parameters syntax
|
||||
|
||||
// variants
|
||||
let func = (input) => {
|
||||
// code here
|
||||
};
|
||||
|
||||
let func = (input) => expression;
|
||||
let func = input => expression;
|
||||
|
||||
func(); // function call
|
||||
|
||||
// return object literal
|
||||
let func = (value) => ({property: value});
|
||||
```
|
||||
|
||||
## Object Oriented Programming
|
||||
|
||||
An object is a collection of related data and/or functionality.
|
||||
|
||||
**Note**: It's not possible to transform a variable in an object simply by using the object assignment.
|
||||
|
||||
```js
|
||||
let variable = value;
|
||||
|
||||
// object literal
|
||||
let obj = {
|
||||
property: value,
|
||||
variable, // same as variable: variable
|
||||
[property]: value // dynamic prop name
|
||||
|
||||
object: {
|
||||
...
|
||||
},
|
||||
|
||||
method: function() {
|
||||
// code here
|
||||
this.propertyName; // reference to object property inside the object
|
||||
}
|
||||
|
||||
method; () => {
|
||||
obj.propertyName; // this is undefined here, use full object name
|
||||
}
|
||||
};
|
||||
|
||||
// access to property (non existant properties will return Undefined)
|
||||
obj.property; // dot notation
|
||||
obj["property"]; // array notation
|
||||
|
||||
// property modification (will add property if missing)
|
||||
obj.property = value; // dot notation
|
||||
obj["property"] = value; // array notation
|
||||
|
||||
obj.func(); //method access
|
||||
|
||||
delete obj.propertyName; // delete property
|
||||
|
||||
Object.keys(obj); // list of all property names
|
||||
Object.entries(obj); // list contents as key-value pairs
|
||||
```
|
||||
|
||||
### Constructors and object instances
|
||||
|
||||
JavaScript uses special functions called **constructor functions** to define and initialize objects and their features.
|
||||
Notice that it has all the features you'd expect in a function, although it doesn't return anything or explicitly create an object — it basically just defines properties and methods.
|
||||
|
||||
```js
|
||||
// constructor function definition
|
||||
function Class(params) {
|
||||
this.property = param;
|
||||
|
||||
this.method = function(params) { /* code here */ }
|
||||
}
|
||||
|
||||
let obj = new Class(params); // object instantiation
|
||||
|
||||
let obj = new Object(); // creates empty object
|
||||
let obj = new Object({
|
||||
// JSON
|
||||
});
|
||||
```
|
||||
|
||||
### Prototypes
|
||||
|
||||
Prototypes are the mechanism by which JavaScript objects *inherit* features from one another.
|
||||
|
||||
JavaScript is often described as a **prototype-based language**; to provide inheritance, objects can have a prototype object, which acts as a template object that it inherits methods and properties from.
|
||||
|
||||
An object's prototype object may also have a prototype object, which it inherits methods and properties from, and so on.
|
||||
This is often referred to as a **prototype chain**, and explains why different objects have properties and methods defined on other objects available to them.
|
||||
If a method is implemented on an object (and not it's prototype) then only that object will heve that method and not all the ones that come from the same prototype.
|
||||
|
||||
```js
|
||||
// constructor function
|
||||
function Obj(param1, ...) {
|
||||
this.param1 = param1,
|
||||
...
|
||||
}
|
||||
|
||||
// method on the object
|
||||
Obj.prototype.method = function(params) {
|
||||
// code here (operate w/ this)
|
||||
}
|
||||
|
||||
let obj = new Obj(args); // object instantiation
|
||||
obj.method(); // call method from prototype
|
||||
```
|
||||
|
||||
### Extending with prototypes
|
||||
|
||||
```js
|
||||
// constructor function
|
||||
function DerivedObj(param1, param2, ...) {
|
||||
Obj.call(this, param1); // use prototype constructor
|
||||
this.param2 = param2;
|
||||
}
|
||||
|
||||
// extend Obj
|
||||
DerivedObj.prototype = Object.create(Obj.prototype);
|
||||
|
||||
// method on object
|
||||
DerivedObj.prototype.method = function() {
|
||||
// code here (operate w/ this)
|
||||
}
|
||||
|
||||
let dobj = new DerivedObj(args); // object instantiation
|
||||
dobj.method(); // call method from prototype
|
||||
```
|
||||
|
||||
### Classes (ES6+)
|
||||
|
||||
```js
|
||||
class Obj {
|
||||
constructor(param1, ...) {
|
||||
this.param1 = param1,
|
||||
...
|
||||
}
|
||||
|
||||
get param1() // getter
|
||||
{
|
||||
return this.param1;
|
||||
}
|
||||
|
||||
func() {
|
||||
// code here (operate w/ this)
|
||||
}
|
||||
|
||||
static func() { } // static method
|
||||
|
||||
// object instantiation
|
||||
let obj = new Obj(param1, ...);
|
||||
obj.func(); // call method
|
||||
```
|
||||
|
||||
### Extending with Classes
|
||||
|
||||
```js
|
||||
class DerivedObj extends Obj {
|
||||
constructor(param1, param2, ...){
|
||||
super(param1); // use superclass constructor
|
||||
this.param2 = param2;
|
||||
}
|
||||
|
||||
newFunc() { }
|
||||
}
|
||||
|
||||
let dobj = DerivedObj();
|
||||
dobj.newFunc();
|
||||
```
|
||||
|
||||
## Deconstruction
|
||||
|
||||
### Object deconstruction
|
||||
|
||||
```js
|
||||
let obj = {
|
||||
property: value,
|
||||
...
|
||||
}
|
||||
|
||||
let { var1, var2 } = obj; // extract values from object into variables
|
||||
let { property: var1, property2 : var2 } = obj; // extract props in variables w/ specified names
|
||||
let { property: var1, var2 = default_value } = obj; // use default values if object has less then expected props
|
||||
```
|
||||
|
||||
### Array Deconstruction
|
||||
|
||||
```js
|
||||
let array = [ 1, 2, 3, 4, 5, 6 ];
|
||||
let [first, , third, , seventh = "missing" ] = array; // extract specific values from array
|
||||
```
|
||||
|
||||
## Serialization
|
||||
|
||||
```js
|
||||
let object = {
|
||||
// object attributes
|
||||
}
|
||||
|
||||
let json = JSON.stringify(object); // serialize object in JSON
|
||||
|
||||
let json = { /* JSON */ };
|
||||
let object = JSON.parse(json); // deserialize to Object
|
||||
```
|
||||
|
||||
## Timing
|
||||
|
||||
### Timers
|
||||
|
||||
Function runs *once* after an interval of time.
|
||||
|
||||
```js
|
||||
// param1, param2, ... are the arguments passed to the function (IE9+)
|
||||
let timerId = setTimeout(func [, milliseconds, param1, param2, ... ]); // wait milliseconds before executing the code (params are read at execution time)
|
||||
|
||||
// works in IE9
|
||||
let timerId = setTimeout(function(){
|
||||
func(param1, param2);
|
||||
}, milliseconds);
|
||||
|
||||
// Anonymous functions with arguments
|
||||
let timerId = setTimeout(function(arg1, ...){
|
||||
// code here
|
||||
}, milliseconds, param1, ...);
|
||||
|
||||
clearTimeout(timerId) // cancel execution
|
||||
|
||||
// example of multiple consecutive schedules
|
||||
let list = [1 , 2, 3, 4, 5, 6, 7, 8, 9, 10, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", -1, -2, -3, -4, -5, -6, -7, -8, -9, -10]
|
||||
function useTimeout(pos=0) {
|
||||
|
||||
setTimeout(function(){
|
||||
console.log(list[pos]);
|
||||
pos += 1; // update value for next call
|
||||
|
||||
if (pos < list.length) { // recursion exit condition
|
||||
useTimeout(pos); // schedule next call with new value
|
||||
}
|
||||
}, 1_000, pos);
|
||||
}
|
||||
|
||||
useTimeout();
|
||||
```
|
||||
|
||||
### `let` vs `var` with `setTimeout`
|
||||
|
||||
```js
|
||||
// let instantiates a new variable for each iteration
|
||||
for (let i = 0; i < 3; ++i) {
|
||||
setTimeout(function() {
|
||||
console.log(i);
|
||||
}, i * 100);
|
||||
}
|
||||
// output: 0, 1, 2
|
||||
|
||||
for (var i = 0; i < 3; ++i) {
|
||||
setTimeout(function() {
|
||||
console.log(i);
|
||||
}, i * 100);
|
||||
}
|
||||
// output: 3, 3, 3
|
||||
```
|
||||
|
||||
### Preserving the context
|
||||
|
||||
```js
|
||||
let obj = {
|
||||
prop: value,
|
||||
|
||||
method1 : function() { /* statement */ }
|
||||
|
||||
method2 : function() {
|
||||
let self = this // memorize context inside method (otherwise callback will not know it)
|
||||
setTimeout(function() { /* code here (uses self) */ })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// better
|
||||
let obj = {
|
||||
prop: value,
|
||||
|
||||
method1 : function() { /* statement */ }
|
||||
|
||||
method2 : function() {
|
||||
setTimeout(() => { /* code here (uses this) */ }) // arrow func does not create new scope, this context preserved
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Intervals
|
||||
|
||||
Function runs regularly with a specified interval. JavaScript is **Single Threaded**.
|
||||
|
||||
```js
|
||||
// param1, param2, ... are the arguments passed to the function (IE9+)
|
||||
let timerId = setInterval(func, milliseconds [, param1, param2, ... ]); // (params are read at execution time)
|
||||
|
||||
// works in IE9
|
||||
let timerId = setInterval(function(){
|
||||
func(param1, param2);
|
||||
}, milliseconds);
|
||||
|
||||
// Anonymous functions with arguments
|
||||
let timerId = setInterval(function(arg1, ...){
|
||||
// code here
|
||||
}, milliseconds, param1, ...);
|
||||
|
||||
clearTimeout(timerId); // cancel execution
|
||||
```
|
||||
|
||||
## DateTime
|
||||
|
||||
A date consists of a year, a month, a day, an hour, a minute, a second, and milliseconds.
|
||||
|
||||
There are generally 4 types of JavaScript date input formats:
|
||||
|
||||
- **ISO Date**: `"2015-03-25"`
|
||||
- Short Date: `"03/25/2015"`
|
||||
- Long Date: `"Mar 25 2015"` or `"25 Mar 2015"`
|
||||
- Full Date: `"Wednesday March 25 2015"`
|
||||
|
||||
```js
|
||||
// constructors
|
||||
new Date();
|
||||
new Date(milliseconds);
|
||||
new Date(dateString);
|
||||
new Date(year, month, day, hours, minutes, seconds, milliseconds);
|
||||
|
||||
// accepts parameters similar to the Date constructor, but treats them as UTC. It returns the number of milliseconds since January 1, 1970, 00:00:00 UTC.
|
||||
Date.UTC(year, month, day, hours, minutes, seconds, milliseconds);
|
||||
|
||||
//static methods
|
||||
Date.now(); // returns the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC.
|
||||
|
||||
// methods
|
||||
let date = new Date();
|
||||
date.toSting(); // returns a string representing the specified Date object
|
||||
date.toUTCString();
|
||||
date.toDateString();
|
||||
date.toTimeString(); // method returns the time portion of a Date object in human readable form in American English.
|
||||
|
||||
|
||||
// get date
|
||||
|
||||
dare.getMonth();
|
||||
date.getMinutes();
|
||||
date.getFullYear();
|
||||
|
||||
// set date
|
||||
date.setFullYear(2020, 0, 14);
|
||||
date.setDate(date.getDate() + 50);
|
||||
|
||||
// parse valid dates
|
||||
let msec = Date.parse("March 21, 2012");
|
||||
let date = new Date(msec);
|
||||
```
|
||||
|
||||
### Comparing Dates
|
||||
|
||||
Comparison operators work also on dates
|
||||
|
||||
```js
|
||||
let date1 = new Date();
|
||||
let date2 = new Date("May 24, 2017 10:50:00");
|
||||
|
||||
if(date1 > date2){
|
||||
console.log('break time');
|
||||
} else {
|
||||
console.log('stay in class');
|
||||
}
|
||||
```
|
||||
|
||||
## [Exports](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export)
|
||||
|
||||
[Firefox CORS not HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSRequestNotHttp)
|
||||
|
||||
**NOTE**: Firefox 68 and later define the origin of a page opened using a `file:///` URI as unique. Therefore, other resources in the same directory or its subdirectories no longer satisfy the CORS same-origin rule. This new behavior is enabled by default using the `privacy.file_unique_origin` preference.
|
||||
|
||||
```json
|
||||
"privacy.file_unique_origin": "false"
|
||||
```
|
||||
|
||||
In `page.html`
|
||||
|
||||
```html
|
||||
<script src="scripts/module.js"></script>
|
||||
<script src="scripts/script.js"></script>
|
||||
```
|
||||
|
||||
In `module.js`:
|
||||
|
||||
```js
|
||||
// exporting individual fractures
|
||||
export default function() {} // one per module
|
||||
export func = () => expression; // zero or more per module
|
||||
|
||||
// Export list
|
||||
export { name1, name2, …, nameN };
|
||||
|
||||
// Renaming exports
|
||||
export { variable1 as name1, variable2 as name2, …, nameN };
|
||||
|
||||
// Exporting destructured assignments with renaming
|
||||
export const { name1, name2: bar } = o;
|
||||
|
||||
// re-export
|
||||
export { func } from "other_script.js"
|
||||
```
|
||||
|
||||
In `script.js`:
|
||||
|
||||
```js
|
||||
import default_func_alias, { func as alias } from "./module.js"; // import default and set alias
|
||||
import { default as default_func_alias, func as alias } from "./module.js"; // import default and set alias
|
||||
|
||||
// use imported functions
|
||||
default_func_alias();
|
||||
alias();
|
||||
```
|
||||
|
||||
```js
|
||||
import * from "./module.js"; // import all
|
||||
|
||||
module.function(); // use imported content with fully qualified name
|
||||
```
|
220
javascript/jquery.md
Normal file
220
javascript/jquery.md
Normal file
|
@ -0,0 +1,220 @@
|
|||
# jQuery Library
|
||||
|
||||
## Including jQuery
|
||||
|
||||
### Download and link the file
|
||||
|
||||
```html
|
||||
<head>
|
||||
<script src="jquery-3.2.1.min.js"></script>
|
||||
</head>
|
||||
```
|
||||
|
||||
### Use a CDN
|
||||
|
||||
```html
|
||||
<head>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||
</head>
|
||||
|
||||
<!-- OR -->
|
||||
|
||||
<head>
|
||||
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.5.1.min.js"></script>
|
||||
</head>
|
||||
```
|
||||
|
||||
### What is a CDN
|
||||
|
||||
A **content delivery network** or **content distribution network** (CDN) is a large distributed system of servers deployed in multiple data centers across the Internet.
|
||||
The goal of a CDN is to serve content to end-users with high availability and high performance.
|
||||
CDNs serve a large fraction of the Internet content today, including web objects (text, graphics and scripts), downloadable objects (media files, software, documents), applications (e-commerce, portals), live streaming media, on-demand streaming media, and social networks.
|
||||
|
||||
## HTML Manipulation
|
||||
|
||||
### [Finding DOM elements](https://api.jquery.com/category/selectors/)
|
||||
|
||||
```js
|
||||
$('tag');
|
||||
$("#id");
|
||||
$(".class");
|
||||
```
|
||||
|
||||
### Manipulating DOM elements
|
||||
|
||||
```js
|
||||
$("p").addClass("special");
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- before -->
|
||||
<p>Welcome to jQuery<p>
|
||||
|
||||
<!-- after -->
|
||||
<p class="special">Welcome to jQuery<p>
|
||||
```
|
||||
|
||||
### Reading Elements
|
||||
|
||||
```html
|
||||
<a id="yahoo" href="http://www.yahoo.com" style="font-size:20px;">Yahoo!</a>
|
||||
```
|
||||
|
||||
```js
|
||||
// find it & store it
|
||||
var link = $('a#yahoo');
|
||||
|
||||
// get info about it
|
||||
link.html(); // 'Yahoo!'
|
||||
link.attr('href'); // 'http://www.yahoo.com'
|
||||
link.css('font-size'); // '20px
|
||||
```
|
||||
|
||||
### Modifying Elements
|
||||
|
||||
```js
|
||||
// jQuery
|
||||
$('a').html('Yahoo!');
|
||||
$('a').attr('href', 'http://www.yahoo.com');
|
||||
$('a').css({'color': 'purple'});
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- before -->
|
||||
<a href="http://www.google.com">Google</a>
|
||||
|
||||
<!-- after -->
|
||||
<a href="http://www.yahoo.com" style="color:purple">Yahoo</a>
|
||||
```
|
||||
|
||||
### Create, Store, Manipulate and inject
|
||||
|
||||
```js
|
||||
let paragraph = $('<p class="intro">Welcome<p>'); // create and store element
|
||||
|
||||
paragraph.css('property', 'value'); // manipulate element
|
||||
|
||||
$("body").append(paragraph); // inject in DOM
|
||||
```
|
||||
|
||||
### Regular DOM Nodes to jQuery Objects
|
||||
|
||||
```js
|
||||
var paragraphs = $('p'); // an array
|
||||
var aParagraph = paragraphs[0]; // a regular DOM node
|
||||
var $aParagraph = $(paragraphs[0]); // a jQuery Object
|
||||
|
||||
// can also use loops
|
||||
for(var i = 0; i < paragraphs.length; i++) {
|
||||
var element = paragraphs[i];
|
||||
var paragraph = $(element);
|
||||
paragraph.html(paragraph.html() + ' WOW!');
|
||||
}
|
||||
```
|
||||
|
||||
## [Events](https://api.jquery.com/category/events/)
|
||||
|
||||
```js
|
||||
var onButtonClick = function() {
|
||||
console.log('clicked!');
|
||||
}
|
||||
|
||||
// with named callback & .on
|
||||
$('button').on('click', onButtonClick);
|
||||
|
||||
// with anonymous callback & .on
|
||||
$('button').on('click', function(){
|
||||
console.log('clicked!');
|
||||
});
|
||||
|
||||
// with .click & named callback
|
||||
$('button').click(onButtonClick);
|
||||
```
|
||||
|
||||
### Preventing Default Event
|
||||
|
||||
```js
|
||||
$('selector').on('event', function(event) {
|
||||
event.preventDefault();
|
||||
// custom logic
|
||||
});
|
||||
```
|
||||
|
||||
## Plugins
|
||||
|
||||
In the HTML, add a `<script>` ag that hotlinks to the CDN or source file:
|
||||
|
||||
```html
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js"><script>
|
||||
```
|
||||
|
||||
In the JavaScript call the jQuery plugin on the DOM:
|
||||
|
||||
```js
|
||||
$("form").validate();
|
||||
```
|
||||
|
||||
**NOTE**: always link to the [minified](https://developers.google.com/speed/docs/insights/MinifyResources) js files.
|
||||
|
||||
## More jQuery
|
||||
|
||||
### Patters & Anti-Patterns
|
||||
|
||||
```js
|
||||
// Pattern: name variables with $var
|
||||
$myVar =$('#myNode');
|
||||
|
||||
// Pattern: store references to callback functions
|
||||
var callback = function(argument){
|
||||
// do something cool
|
||||
};
|
||||
|
||||
$(document).on('click', 'p', myCallback);
|
||||
|
||||
// Anti-pattern: anonymous functions
|
||||
$(document).on('click', 'p', function(argument){
|
||||
// do something anonymous
|
||||
});
|
||||
```
|
||||
|
||||
### Chaining
|
||||
|
||||
```js
|
||||
banner.css('color', 'red');
|
||||
banner.html('Welcome!');
|
||||
banner.show();
|
||||
|
||||
// same as:
|
||||
banner.css('color', 'red').html('Welcome!').show();
|
||||
|
||||
// same as:
|
||||
banner.css('color', 'red')
|
||||
.html('Welcome!')
|
||||
.show();
|
||||
```
|
||||
|
||||
### DOM Readiness
|
||||
|
||||
DOM manipulation and event binding doesn't work if the `<script>` is in the `<head>`
|
||||
|
||||
```js
|
||||
$(document).ready(function() {
|
||||
// the DOM is fully loaded
|
||||
});
|
||||
|
||||
$(window).on('load', function(){
|
||||
// the DOM and all assets (including images) are loaded
|
||||
});
|
||||
```
|
||||
|
||||
## AJAX (jQuery `1.5`+)
|
||||
|
||||
```js
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: 'some.php',
|
||||
data: { name: 'John', location: 'Boston'}
|
||||
})
|
||||
.done(function(msg){alert('Data Saved: '+ msg);})
|
||||
.fail(function(jqXHR, textStatus){alert('Request failed: '+ textStatus);});
|
||||
```
|
103
javascript/react/react-router.md
Normal file
103
javascript/react/react-router.md
Normal file
|
@ -0,0 +1,103 @@
|
|||
# [React Router](https://reactrouter.com)
|
||||
|
||||
Popular routing library. Allows to specify a route through React components, declaring which component is to be loaded for a given URL.
|
||||
|
||||
Key Components:
|
||||
|
||||
- **Router**: wrap the app entry-point, usually `BrowserRouter`
|
||||
- **Route**: "Load this component for this URL"
|
||||
- **Link**: react-managed anchors that won't post back to the browser
|
||||
|
||||
## Routers
|
||||
|
||||
Router Types:
|
||||
|
||||
- *HashRouter*: `#route`, adds hashes to the URLs
|
||||
- *BrowserRouter*: `/route`, uses HTML5 history API to provide clean URLs
|
||||
- *MemoryRouter*: no URL
|
||||
|
||||
```js
|
||||
// index.js
|
||||
|
||||
//other imports ...
|
||||
|
||||
import { BrowserRouter as Router } from "react-router-dom";
|
||||
|
||||
React.render(
|
||||
<Router>
|
||||
<App />
|
||||
</Router>,
|
||||
document.getElementById("DomID");
|
||||
)
|
||||
```
|
||||
|
||||
```js
|
||||
// Component.js
|
||||
import { Route, Route } from "react-router-dom";
|
||||
|
||||
<div>
|
||||
{/* match route pattern exactly, all sub-routes will be matched otherwise */}
|
||||
<Route path="/" exact element={<Component props={props} />} />
|
||||
<Route path="/route" element={<Component props={props} />} />
|
||||
...
|
||||
</div>
|
||||
|
||||
// only one child can match, similar to Route-case
|
||||
<Routes>
|
||||
<Route path="/" exact element={<Component props={props} />} />
|
||||
<Route path="/route" element={<Component props={props} />} />
|
||||
<Route component={PageNotFound} /> {/* matches all non-existent URLs */}
|
||||
</Route>
|
||||
```
|
||||
|
||||
### URL Parameters & Query String
|
||||
|
||||
```js
|
||||
// Given
|
||||
<Route path="/route/:placeholder" element={<Component props={props} />} />
|
||||
// URL: app.com/route/sub-route?param=value
|
||||
|
||||
function Component(props) {
|
||||
props.match.params.placeholder; // sub-route
|
||||
props.location.query; // { param: value }
|
||||
props.location.pathname; // /route/sub-route?param=value
|
||||
}
|
||||
```
|
||||
|
||||
### Redirecting
|
||||
|
||||
```js
|
||||
import { Redirect } from "react-router-dom";
|
||||
|
||||
// redirects to another URL, should'nt be rendered on component mount but after an action
|
||||
<Redirect to="/route" />
|
||||
<Redirect from="/old-route" to="/new-route" />
|
||||
{ condition && <Redirect to="/route" /> } // redirect if condition is true
|
||||
|
||||
// or redirect manipulating the history (always in props)
|
||||
props.history.push("/new-route");
|
||||
```
|
||||
|
||||
### Prompts
|
||||
|
||||
```js
|
||||
import { Prompt } from "react-router-dom";
|
||||
|
||||
// displays a prompt when the condition is true
|
||||
<Prompt when={condition} message="prompt message" />
|
||||
```
|
||||
|
||||
## Link
|
||||
|
||||
Clicks on a link created with React-Router will be captured by react an all the routing will happen client side.
|
||||
|
||||
```js
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
// TARGET: <Route path="/route/:itemId" />
|
||||
<Link to="/route/1">Text</Link>
|
||||
|
||||
// add styling attributes to the rendered element when it matches the current URL.
|
||||
<NavLink to="/route" exact activeClassName="class">Text</NavLink>
|
||||
<NavLink to="/route" activeStyle={ { cssProp: value } }>Text</NavLink>
|
||||
```
|
150
javascript/react/react-tests.md
Normal file
150
javascript/react/react-tests.md
Normal file
|
@ -0,0 +1,150 @@
|
|||
# Testing React
|
||||
|
||||
## [Jest](https://jestjs.io/)
|
||||
|
||||
### Jest Configuration
|
||||
|
||||
```js
|
||||
// jest.config.js
|
||||
module.exports = {
|
||||
testEnvironment: 'jsdom',
|
||||
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'node'],
|
||||
setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'], // add testing-library methods to expect()
|
||||
transform: { '^.+\\.tsx?$': 'ts-jest'} // use ts-jest fo ts files
|
||||
}
|
||||
```
|
||||
|
||||
### Jest Tests
|
||||
|
||||
[Expect docs](https://jestjs.io/docs/expect)
|
||||
|
||||
```js
|
||||
// .spec.js or .test.js
|
||||
it("test description", () => {
|
||||
// test body
|
||||
expect(expected).toEqual(actual);
|
||||
});
|
||||
|
||||
// group related tests
|
||||
describe("test group name", () => {
|
||||
it(/* ... */);
|
||||
it(/* ... */);
|
||||
});
|
||||
```
|
||||
|
||||
### Snapshots
|
||||
|
||||
In `Component.Snapshots.js`:
|
||||
|
||||
```js
|
||||
import React from "react";
|
||||
import renderer from "react-test-renderer";
|
||||
|
||||
import Component from "./path/to/Component";
|
||||
// import mock data if necessary
|
||||
|
||||
it("test description", () => {
|
||||
// renders the DOM tree of the component
|
||||
const tree = renderer.create(<Component funcProp={jest.fn() /* mock function */} /* component props */ />);
|
||||
|
||||
// save a snapshot of the component at this point in time ( in __snapshots__ folder)
|
||||
// in future test it will be checked to avoid regressions
|
||||
// can be updated during jest --watch pressing "u"
|
||||
expect(tree).matchSnapshot();
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## [Enzyme](https://enzymejs.github.io/enzyme/)
|
||||
|
||||
### Enzyme Configuration
|
||||
|
||||
```js
|
||||
// testSetup.js
|
||||
import { configure } from "enzyme";
|
||||
import Adapter from "enzyme-adapter-react-<version>";
|
||||
|
||||
configure({ adapter: new Adapter() });
|
||||
```
|
||||
|
||||
### Enzyme Tests
|
||||
|
||||
In `Component.test.js`:
|
||||
|
||||
```js
|
||||
import React from "react";
|
||||
import { shallow, mount } from "enzyme";
|
||||
// eventual wrapper components (react-router, react-redux's provider, ...) for mount render
|
||||
|
||||
// shallow renders single component w/o children, no DOM generated
|
||||
// mount renders component w/ it's children
|
||||
|
||||
import Component from "./path/to/Component";
|
||||
|
||||
// factory to setup shallow test easily
|
||||
function testHelper(args) {
|
||||
const defaultProps = { /* default value for props in each test */ };
|
||||
|
||||
const props = { ...defaultProps, ...args };
|
||||
return shallow(<Component {...props} />);
|
||||
}
|
||||
|
||||
// shallow rendering test
|
||||
it("test description", () => {
|
||||
const dom = testHelper(/* optional args */);
|
||||
// or
|
||||
const dom = shallow(<Component /* props */ />);
|
||||
|
||||
// check a property of expected component
|
||||
// selector can be from raw JSX (name of a component)
|
||||
expect(dom.find("selector").property).toBe(expected);
|
||||
});
|
||||
|
||||
// mount rendering test
|
||||
if("test description" () => {
|
||||
const dom = mount(
|
||||
<WrapperComponent>
|
||||
<Component /* props *//>
|
||||
</WrapperComponent>
|
||||
);
|
||||
|
||||
// selector has to be HTML selector since the component is rendered completely
|
||||
// possible to test child components
|
||||
expect(dom.find("selector").property).toBe(expected);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/)
|
||||
|
||||
Encourages to write test based on what the user sees. So components are always *mounted* and fully rendered.
|
||||
|
||||
### React Testing Library Tests
|
||||
|
||||
In `Components.test.js`:
|
||||
|
||||
```js
|
||||
import React from "react";
|
||||
import { cleanup, render } from "@testing-library/react";
|
||||
|
||||
import Component from "./path/to/Component";
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
// factory to setup test easily
|
||||
function testHelper(args) {
|
||||
const defaultProps = { /* default value for props in each test */ };
|
||||
|
||||
const props = { ...defaultProps, ...args };
|
||||
return render(<Component {...props} />);
|
||||
}
|
||||
|
||||
it("test description", () => {
|
||||
const { getByText } = testHelper();
|
||||
|
||||
// react testing library func
|
||||
getByText("text"); // check if test is present in the rendered component
|
||||
});
|
||||
```
|
261
javascript/react/react.md
Normal file
261
javascript/react/react.md
Normal file
|
@ -0,0 +1,261 @@
|
|||
# React
|
||||
|
||||
## Components
|
||||
|
||||
There are two types of react components:
|
||||
|
||||
- Function Components
|
||||
- Class Components
|
||||
|
||||
Both types can be stateful and have side effects or be purely presentational.
|
||||
|
||||
```jsx
|
||||
// functional component
|
||||
const Component = (props) => {
|
||||
return (
|
||||
<domElementOrComponent... />
|
||||
);
|
||||
}
|
||||
|
||||
// class component
|
||||
class Component extends React.Component {
|
||||
return (
|
||||
<domElementOrComponent... />
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
*NOTE*: a component name *must* start with an uppercase letter.
|
||||
|
||||
Every components has two inputs: *props* and *state*. The props input is explicit while the state is implicit.
|
||||
State is used to determine the changes and when to re-render.
|
||||
Within the component state can be changed while the props object represent fixed input values.
|
||||
|
||||
JSX syntax can represent HTML but gets converted to pure JavaScript before being sent to the browser:
|
||||
|
||||
```js
|
||||
// JSX
|
||||
const element = (
|
||||
<h1 className="greeting">Hello, world!</h1>
|
||||
);
|
||||
|
||||
// compiled JS shipped to browser
|
||||
const element = React.createElement(
|
||||
'h1', // HTML tag name
|
||||
{className: 'greeting'}, // attrs as JSON
|
||||
'Hello, world!' // tag content (can be nested component)
|
||||
);
|
||||
```
|
||||
|
||||
### App Entry-point
|
||||
|
||||
```js
|
||||
const container = document.getElementById('root')!;
|
||||
const root = createRoot(container);
|
||||
|
||||
const element = <h1s>Hello World</h1>
|
||||
root.render(element)
|
||||
```
|
||||
|
||||
### Dynamic Expressions
|
||||
|
||||
```js
|
||||
<tag>{expression}</tag> // expression is evaluated an it's result is displayed
|
||||
<tag onEvent={funcReference}>{expression}</tag>
|
||||
<tag onEvent={() => func(args)}>{expression}</tag>
|
||||
```
|
||||
|
||||
### Props
|
||||
|
||||
```js
|
||||
<Component propName={value} /> // pass a value the component
|
||||
<Component propName={funcReference} /> // pass a function to the component
|
||||
|
||||
function Component(props) {
|
||||
// use props with {props.propName}
|
||||
}
|
||||
|
||||
class Component extends React.Component{
|
||||
// use props with {this.props.propName}
|
||||
render()
|
||||
}
|
||||
```
|
||||
|
||||
### Simple Function Component
|
||||
|
||||
```js
|
||||
// Button.js
|
||||
import { useState } from "react";
|
||||
|
||||
function Button() {
|
||||
const [count, setCount] = useState(0); // hook
|
||||
|
||||
const handleCLick = () => setCount(count + 1); // logic
|
||||
|
||||
// JSX
|
||||
return (
|
||||
<button onClick={handleCLick}>
|
||||
{count}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default Button;
|
||||
```
|
||||
|
||||
### Simple Class Component
|
||||
|
||||
```js
|
||||
class Button extends React.Component {
|
||||
|
||||
state = {count: 0};
|
||||
//or
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {count: 0};
|
||||
}
|
||||
|
||||
componentDidMount() {} // called on successful component mount
|
||||
|
||||
handleClick = () => {
|
||||
this.setState({ count: this.state.count + 1 });
|
||||
}
|
||||
// or
|
||||
handleClick = () => {
|
||||
this.setState((state, props) => ({ count: state.count + props.increment }) );
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<button onClick={this.handleClick}>
|
||||
{this.state.count}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Nesting Components
|
||||
|
||||
```js
|
||||
import { useState } from "react";
|
||||
|
||||
function Button(props) {
|
||||
return (
|
||||
<button onClick={props.onClickFunc}>
|
||||
+1
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function Display (props) {
|
||||
return (
|
||||
<div>{props.message}</div>
|
||||
);
|
||||
}
|
||||
|
||||
function App() {
|
||||
|
||||
// state must be declare in the outer component it can be passed to each children
|
||||
const [count, setCount] = useState(0);
|
||||
const incrementCounter = () => setCount(count + 1);
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<Button onClickFunc={incrementCounter}/>
|
||||
<Display message={count}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
### User Input (Forms)
|
||||
|
||||
```js
|
||||
function Form() {
|
||||
const [userName, setUserName] = useState("");
|
||||
|
||||
handleSubmit = (event) => {
|
||||
event.preventDefault();
|
||||
// ...
|
||||
}
|
||||
|
||||
return(
|
||||
<form onSubmit={handleSubmit}>
|
||||
<input
|
||||
type="text"
|
||||
value={userName} // controlled component
|
||||
onChange={(event) => setUserName(event.target.value)} // needed to update UI on dom change
|
||||
required
|
||||
/>
|
||||
<button></button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Lists of Components
|
||||
|
||||
```js
|
||||
// ...
|
||||
<div>
|
||||
{array.map(item => <Component key={uniqueID}>)}
|
||||
</div>
|
||||
// ...
|
||||
```
|
||||
|
||||
**NOTE**: The `key` attribute of the component is needed to identify a particular item. It's most useful if the list has to be sorted.
|
||||
|
||||
## Hooks
|
||||
|
||||
### `useState`
|
||||
|
||||
Hook used to create a state object.
|
||||
|
||||
`useState()` results:
|
||||
|
||||
- state object (getter)
|
||||
- updater function (setter)
|
||||
|
||||
```js
|
||||
const [state, setState] = useState(default);
|
||||
```
|
||||
|
||||
### `useEffect`
|
||||
|
||||
Hook used to trigger an action on each render of the component or when one of the watched items changes.
|
||||
|
||||
```js
|
||||
|
||||
useEffect(() => {
|
||||
// "side effects" operations
|
||||
|
||||
return () => {/* clean up side effect */} // optional
|
||||
}, [/* list of watched items, empty triggers once */]);
|
||||
```
|
||||
|
||||
### Custom Hooks
|
||||
|
||||
```js
|
||||
// hook definitions
|
||||
const useCustomHook = () => {
|
||||
// eventual state definitions
|
||||
|
||||
// eventual function definitions
|
||||
|
||||
// ...
|
||||
|
||||
return { obj1, obj2, ... };
|
||||
}
|
||||
|
||||
const Component(){
|
||||
// retrieve elements from the hook
|
||||
const {
|
||||
obj1,
|
||||
obj2,
|
||||
...
|
||||
} = useCustomHook();
|
||||
}
|
||||
```
|
156
javascript/react/redux-tests.md
Normal file
156
javascript/react/redux-tests.md
Normal file
|
@ -0,0 +1,156 @@
|
|||
# Redux Testing
|
||||
|
||||
## Tests for Connected Components
|
||||
|
||||
Connected components are wrapped in a call to `connect`. Way of solving the problem:
|
||||
|
||||
- Wrap component with `<Provider>`. Added benefit: new store dedicated to tests.
|
||||
- Add named export for unconnected component.
|
||||
|
||||
In `Component.js`:
|
||||
|
||||
```js
|
||||
export function Component(props) { /* ... */ } // export unconnected component
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Component) // default export of connected component
|
||||
```
|
||||
|
||||
In `Component.test.js`:
|
||||
|
||||
```js
|
||||
import React from "react";
|
||||
// import enzyme or react testing library
|
||||
|
||||
// import mock data
|
||||
import { Component } from "path/to/Component"; // import unconnected component
|
||||
|
||||
// factory to setup test easily
|
||||
function testHelper(args) {
|
||||
const defaultProps = {
|
||||
/* default value for props in each test and required props */,
|
||||
history = {} // normally injected by react-router, could also import the router
|
||||
};
|
||||
|
||||
const props = { ...defaultProps, ...args };
|
||||
return mount(<Component {...props} />); // or render if using react testing library
|
||||
}
|
||||
|
||||
it("test description", () => {
|
||||
const dom = testHelper();
|
||||
|
||||
// simulate page iteration
|
||||
dom.find("selector").simulate("<event>");
|
||||
|
||||
// find changed component
|
||||
// test expected behaviour of component
|
||||
});
|
||||
```
|
||||
|
||||
## Tests for Action Creators
|
||||
|
||||
```js
|
||||
import * as actions from "path/to/actionCreators";
|
||||
// import eventual action types constants
|
||||
// import mock data
|
||||
|
||||
it("test description", () => {
|
||||
const data = /* mock data */
|
||||
const expectedAction = { type: TYPE, /* ... */ };
|
||||
|
||||
const actualAction = actions.actionCreator(data);
|
||||
|
||||
expect(actualAction).toEqual(expectedAction);
|
||||
});
|
||||
```
|
||||
|
||||
## Tests for Reducers
|
||||
|
||||
```js
|
||||
import reducer from "path/to/reducer";
|
||||
import * as actions from "path/to/actionCreators";
|
||||
|
||||
it("test description", () => {
|
||||
const initialState = /* state before the action */;
|
||||
const finalState = /* expected state after the action */
|
||||
const data = /* data passed to the action creator */;
|
||||
|
||||
const action = actions.actionCreator(data);
|
||||
const newState = reducer(initialState, action);
|
||||
|
||||
expect(newState).toEqual(finalState);
|
||||
});
|
||||
```
|
||||
|
||||
## Tests for the Store
|
||||
|
||||
```js
|
||||
import { createStore } from "redux";
|
||||
|
||||
import rootReducer from "path/to/rootReducer";
|
||||
import initialState from "path/to/initialState";
|
||||
import * as actions from "path/to/actionCreators";
|
||||
|
||||
it("test description", () => {
|
||||
const store = createStore(storeReducer, initialState);
|
||||
|
||||
const expectedState = /* state after the update */
|
||||
|
||||
const data = /* action creator input */;
|
||||
const action = actions.actionCreator(data);
|
||||
store.dispatch(action);
|
||||
|
||||
const state = store.getState();
|
||||
expect(state).toEqual(expectedState);
|
||||
});
|
||||
```
|
||||
|
||||
## Tests for Thunks
|
||||
|
||||
Thunk testing requires the mocking of:
|
||||
|
||||
- store (using `redux-mock-store`)
|
||||
- HTTP calls (using `fetch-mock`)
|
||||
|
||||
```js
|
||||
import thunk from "redux-thunk";
|
||||
import fetchMock from "fetch-mock";
|
||||
import configureMockStore from "redux-mock-store";
|
||||
|
||||
// needed for testing async thunks
|
||||
const middleware = [thunk]; // mock middlewares
|
||||
const mockStore = configureMockStore(middleware); // mock the store
|
||||
|
||||
import * as actions from "path/to/actionCreators";
|
||||
// import eventual action types constants
|
||||
// import mock data
|
||||
|
||||
describe("Async Actions", () => {
|
||||
afterEach(() => {
|
||||
fetchMock.restore(); // init fetch mock for each test
|
||||
});
|
||||
|
||||
it("test description", () => {
|
||||
// mimic API call
|
||||
fetchMock.mock(
|
||||
"*", // capture any fetch call
|
||||
{
|
||||
body: /* body contents */,
|
||||
headers: { "content-type": "application/json" }
|
||||
}
|
||||
);
|
||||
|
||||
// expected action fired from the thunk
|
||||
const expectedActions = [
|
||||
{ type: TYPE, /* ... */ },
|
||||
{ type: TYPE, /* ... */ }
|
||||
];
|
||||
|
||||
const store = mockStore({ data: value, ... }); // init mock store
|
||||
|
||||
return store.dispatch(actions.actionCreator()) // act
|
||||
.then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions); // assert
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
465
javascript/react/redux.md
Normal file
465
javascript/react/redux.md
Normal file
|
@ -0,0 +1,465 @@
|
|||
# [Redux](https://redux.js.org/)
|
||||
|
||||
Redux is a pattern and library for managing and updating application state, using events called *actions*. It serves as a centralized store for state that needs to be used across the entire application, with rules ensuring that the state can only be updated in a predictable fashion.
|
||||
|
||||
## Actions, Store, Immutability & Reducers
|
||||
|
||||
### Actions & Action Creators
|
||||
|
||||
An **Action** is a plain JavaScript object that has a `type` field. An action object can have other fields with additional information about what happened.
|
||||
By convention, that information is stored in a field called `payload`.
|
||||
|
||||
**Action Creators** are functions that create and return action objects.
|
||||
|
||||
```js
|
||||
function actionCreator(data)
|
||||
{
|
||||
return { type: ACTION_TYPE, payload: data }; // action obj
|
||||
}
|
||||
```
|
||||
|
||||
### Store
|
||||
|
||||
The current Redux application state lives in an object called the **store**.
|
||||
The store is created by passing in a reducer, and has a method called `getState` that returns the current state value.
|
||||
|
||||
The Redux store has a method called `dispatch`. The only way to update the state is to call `store.dispatch()` and pass in an action object.
|
||||
The store will run its reducer function and save the new state value inside.
|
||||
|
||||
**Selectors** are functions that know how to extract specific pieces of information from a store state value.
|
||||
|
||||
In `initialState.js`;
|
||||
|
||||
```js
|
||||
export default {
|
||||
// initial state here
|
||||
}
|
||||
```
|
||||
|
||||
In `configStore.js`:
|
||||
|
||||
```js
|
||||
// configStore.js
|
||||
import { createStore, applyMiddleware, compose } from "redux";
|
||||
|
||||
export function configStore(initialState) {
|
||||
const composeEnhancers =
|
||||
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; // support for redux devtools
|
||||
|
||||
return createStore(
|
||||
rootReducer,
|
||||
initialState,
|
||||
composeEnhancers(applyMiddleware(middleware, ...))
|
||||
);
|
||||
}
|
||||
|
||||
// available functions & methods
|
||||
replaceReducer(newReducer); // replace an existing reducer, useful for Hot Reload
|
||||
store.dispatch(action); // trigger a state change based on an action
|
||||
store.subscribe(listener);
|
||||
store.getState(); // retrieve current state
|
||||
```
|
||||
|
||||
### Reducers
|
||||
|
||||
**Reducers** are functions that receives the current state and an action, decide how to update the state if necessary, and return the new state.
|
||||
|
||||
Reducers must **always** follow some specific rules:
|
||||
|
||||
- They should only calculate the new state value based on the `state` and `action` arguments
|
||||
- They are not allowed to modify the existing `state`.
|
||||
Instead, they must make *immutable updates*, by copying the existing `state` and making changes to the copied values.
|
||||
- They must not do any asynchronous logic, calculate random values, or cause other "side effects"
|
||||
|
||||
```js
|
||||
import initialState from "path/to/initialState";
|
||||
|
||||
function reducer(state = initialState, action) {
|
||||
switch(action.type){
|
||||
case "ACTION_TYPE":
|
||||
return { ...state, prop: value }; // return modified copy of state (using spread operator)
|
||||
break;
|
||||
|
||||
default:
|
||||
return state; // return unchanged state (NEEDED)
|
||||
}
|
||||
}
|
||||
|
||||
// combining reducers
|
||||
import { combineReducers } from "redux";
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
entity: entityReducer.
|
||||
...
|
||||
});
|
||||
```
|
||||
|
||||
**NOTE**: multiple reducers can be triggered by the same action since each one operates on a different portion of the state.
|
||||
|
||||
## [React-Redux](https://react-redux.js.org/)
|
||||
|
||||
### Container vs Presentational Components
|
||||
|
||||
Container Components:
|
||||
|
||||
- Focus on how thing work
|
||||
- Aware of Redux
|
||||
- Subscribe to Redux State
|
||||
- Dispatch Redux actions
|
||||
|
||||
Presentational Components:
|
||||
|
||||
- Focus on how things look
|
||||
- Unaware of Redux
|
||||
- Read data from props
|
||||
- Invoke callbacks on props
|
||||
|
||||
### Provider Component & Connect
|
||||
|
||||
Used at the root component and wraps all the application.
|
||||
|
||||
```js
|
||||
// index.js
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import { configStore } from 'path/to/configStore';
|
||||
import initialState from "path/to/initialState";
|
||||
import App from './App';
|
||||
|
||||
const store = configStore(initialState);
|
||||
|
||||
const rootElement = document.getElementById('root');
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
</Provider>,
|
||||
rootElement
|
||||
);
|
||||
```
|
||||
|
||||
```js
|
||||
// Component.js
|
||||
import { connect } from 'react-redux';
|
||||
import { increment, decrement, reset } from './actionCreators';
|
||||
|
||||
// const Component = ...
|
||||
|
||||
// specifies which state is passed to the component (called on state change)
|
||||
const mapStateToProps = (state, ownProps /* optional */) => {
|
||||
// structure of the props passed to the component
|
||||
return { propName: state.property };
|
||||
};
|
||||
|
||||
// specifies the action passed to a component (the key is the name that the prop will have )
|
||||
const mapDispatchToProps = { actionCreator: actionCreator };
|
||||
// or
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
// wrap action creators
|
||||
actionCreator: (args) => dispatch(actionCreator(args))
|
||||
};
|
||||
}
|
||||
// or
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actionCreator: bindActionCreators(actionCreator, dispatch),
|
||||
actions: bindActionCreators(allActionCreators, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
// both args are optional
|
||||
// if mapDispatch is missing the dispatch function is added to the props
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Component);
|
||||
```
|
||||
|
||||
## Async Operations with [Redux-Thunk](https://github.com/reduxjs/redux-thunk)
|
||||
|
||||
**Note**: Redux middleware runs *after* and action and *before* it's reducer.
|
||||
|
||||
Redux-Thunk allows to return functions instead of objects from action creators.
|
||||
A "thunk" is a function that wraps an expression to delay it's evaluation.
|
||||
|
||||
In `configStore.js`:
|
||||
|
||||
```js
|
||||
import { createStore, applyMiddleware, compose } from "redux";
|
||||
import thunk from "redux-thunk";
|
||||
|
||||
function configStore(initialState) {
|
||||
const composeEnhancers =
|
||||
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; // support for redux devtools
|
||||
|
||||
return createStore(
|
||||
rootReducer,
|
||||
initialState,
|
||||
composeEnhancers(applyMiddleware(thunk, ...)) // add thunks middleware
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
// usually action on async func success
|
||||
function actionCreator(arg) {
|
||||
return { type: TYPE, data: arg };
|
||||
}
|
||||
|
||||
export function thunk() {
|
||||
return function (dispatch) { // redux-thunk injects dispatch as arg
|
||||
return asyncFunction().then((data) => { // async function returns a promise
|
||||
dispatch(actionCreator(data));
|
||||
})
|
||||
.catch((error) => {
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// or using async/await
|
||||
export async function thunk() {
|
||||
return function (dispatch) { // redux-thunk injects dispatch as arg
|
||||
try {
|
||||
let data = await asyncFunction();
|
||||
return dispatch(actionCreator(data));
|
||||
} catch(error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## [Redux-Toolkit](https://redux-toolkit.js.org/)
|
||||
|
||||
The Redux Toolkit package is intended to be the standard way to write Redux logic. It was originally created to help address three common concerns about Redux.
|
||||
|
||||
Redux Toolkit also includes a powerful data fetching and caching capability dubbed "RTK Query". It's included in the package as a separate set of entry points. It's optional, but can eliminate the need to hand-write data fetching logic yourself.
|
||||
|
||||
These tools should be beneficial to all Redux users. Whether you're a brand new Redux user setting up your first project, or an experienced user who wants to simplify an existing application, Redux Toolkit can help you make your Redux code better.
|
||||
Installation
|
||||
Using Create React App
|
||||
|
||||
The recommended way to start new apps with React and Redux is by using the official Redux+JS template or Redux+TS template for Create React App, which takes advantage of Redux Toolkit and React Redux's integration with React components.
|
||||
|
||||
```sh
|
||||
# Redux + Plain JS template
|
||||
npx create-react-app my-app --template redux
|
||||
|
||||
# Redux + TypeScript template
|
||||
npx create-react-app my-app --template redux-typescript
|
||||
```
|
||||
|
||||
Redux Toolkit includes these APIs:
|
||||
|
||||
- [`configureStore()`][cfg_store]: wraps `createStore` to provide simplified configuration options and good defaults.
|
||||
It can automatically combines slice reducers, adds whatever Redux middleware supplied, includes redux-thunk by default, and enables use of the Redux DevTools Extension.
|
||||
|
||||
- [`createReducer()`][new_reducer]: that lets you supply a lookup table of action types to case reducer functions, rather than writing switch statements.
|
||||
In addition, it automatically uses the `immer` library to let you write simpler immutable updates with normal mutative code, like `state.todos[3].completed = true`.
|
||||
|
||||
- [`createAction()`][new_action]: generates an action creator function for the given action type string.
|
||||
The function itself has `toString()` defined, so that it can be used in place of the type constant.
|
||||
- [`createSlice()`][new_slice]: accepts an object of reducer functions, a slice name, and an initial state value, and automatically generates a slice reducer with corresponding action creators and action types.
|
||||
- [`createAsyncThunk`][new_async_thunk]: accepts an action type string and a function that returns a promise, and generates a thunk that dispatches pending/fulfilled/rejected action types based on that promise
|
||||
- [`createEntityAdapter`][entity_adapt]: generates a set of reusable reducers and selectors to manage normalized data in the store
|
||||
- The `createSelector` utility from the Reselect library, re-exported for ease of use.
|
||||
|
||||
[cfg_store]: https://redux-toolkit.js.org/api/configureStore
|
||||
[new_reducer]: https://redux-toolkit.js.org/api/createReducer
|
||||
[new_action]: https://redux-toolkit.js.org/api/createAction
|
||||
[new_slice]: https://redux-toolkit.js.org/api/createSlice
|
||||
[new_async_thunk]: https://redux-toolkit.js.org/api/createAsyncThunk
|
||||
[entity_adapt]: https://redux-toolkit.js.org/api/createEntityAdapter
|
||||
|
||||
### [`configureStore`](https://redux-toolkit.js.org/api/configureStore)
|
||||
|
||||
Included Default Middleware:
|
||||
|
||||
- Immutability check middleware: deeply compares state values for mutations. It can detect mutations in reducers during a dispatch, and also mutations that occur between dispatches.
|
||||
When a mutation is detected, it will throw an error and indicate the key path for where the mutated value was detected in the state tree. (Forked from `redux-immutable-state-invariant`.)
|
||||
|
||||
- Serializability check middleware: a custom middleware created specifically for use in Redux Toolkit
|
||||
Similar in concept to `immutable-state-invariant`, but deeply checks the state tree and the actions for non-serializable values such as functions, Promises, Symbols, and other non-plain-JS-data values
|
||||
When a non-serializable value is detected, a console error will be printed with the key path for where the non-serializable value was detected.
|
||||
|
||||
- In addition to these development tool middleware, it also adds `redux-thunk` by default, since thunks are the basic recommended side effects middleware for Redux.
|
||||
|
||||
Currently, the return value of `getDefaultMiddleware()` is:
|
||||
|
||||
```js
|
||||
// development
|
||||
const middleware = [thunk, immutableStateInvariant, serializableStateInvariant]
|
||||
|
||||
// production
|
||||
const middleware = [thunk]
|
||||
```
|
||||
|
||||
```js
|
||||
|
||||
import { combineReducers } from 'redux'
|
||||
import { configureStore } from '@reduxjs/toolkit'
|
||||
import monitorReducersEnhancer from './enhancers/monitorReducers'
|
||||
import loggerMiddleware from './middleware/logger'
|
||||
import usersReducer from './usersReducer'
|
||||
import postsReducer from './postsReducer'
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
users: usersReducer,
|
||||
posts: postsReducer,
|
||||
})
|
||||
|
||||
const store = configureStore({
|
||||
// reducers combined automatically
|
||||
reducer: rootReducer,
|
||||
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(loggerMiddleware),
|
||||
enhancers: [monitorReducersEnhancer]
|
||||
})
|
||||
|
||||
export default store
|
||||
```
|
||||
|
||||
### [`createAction`](https://redux-toolkit.js.org/api/createAction)
|
||||
|
||||
```js
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
const increment = createAction<number | undefined>('counter/increment');
|
||||
|
||||
const action = increment(); // { type: 'counter/increment' }
|
||||
const action = increment(3); // { type: 'counter/increment', payload: 3 }
|
||||
|
||||
increment.toString(); // 'counter/increment'
|
||||
```
|
||||
|
||||
### [`createReducer`](https://redux-toolkit.js.org/api/createReducer)
|
||||
|
||||
```js
|
||||
import { createAction, createReducer } from '@reduxjs/toolkit'
|
||||
|
||||
interface CounterState {
|
||||
value: number
|
||||
}
|
||||
|
||||
const increment = createAction('counter/increment')
|
||||
const decrement = createAction('counter/decrement')
|
||||
const incrementByAmount = createAction<number>('counter/incrementByAmount')
|
||||
|
||||
const initialState = { value: 0 } as CounterState
|
||||
|
||||
const counterReducer = createReducer(initialState, (builder) => {
|
||||
builder
|
||||
.addCase(increment, (state, action) => {
|
||||
state.value++
|
||||
})
|
||||
.addCase(decrement, (state, action) => {
|
||||
state.value--
|
||||
})
|
||||
.addCase(incrementByAmount, (state, action) => {
|
||||
state.value += action.payload
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### [`createSlice`](https://redux-toolkit.js.org/api/createSlice)
|
||||
|
||||
A function that accepts an initial state, an object of reducer functions, and a "slice name", and automatically generates action creators and action types that correspond to the reducers and state.
|
||||
|
||||
Internally, it uses `createAction` and `createReducer`, so it's possible to use Immer to write "mutating" immutable updates.
|
||||
|
||||
**Note**: action types will have the `<slice-name>/<reducer-name>` shape.
|
||||
|
||||
```js
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||
|
||||
interface CounterState {
|
||||
value: number
|
||||
}
|
||||
|
||||
const initialState = { value: 0 } as CounterState
|
||||
|
||||
const counterSlice = createSlice({
|
||||
name: 'counter',
|
||||
initialState,
|
||||
reducers: {
|
||||
increment(state) {
|
||||
state.value++
|
||||
},
|
||||
decrement(state) {
|
||||
state.value--
|
||||
},
|
||||
incrementByAmount(state, action: PayloadAction<number>) {
|
||||
state.value += action.payload
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export const { increment, decrement, incrementByAmount } = counterSlice.actions
|
||||
export default counterSlice.reducer
|
||||
```
|
||||
|
||||
### [`createAsyncThunk`](https://redux-toolkit.js.org/api/createAsyncThunk)
|
||||
|
||||
The function `createAsyncThunk` returns a standard Redux thunk action creator.
|
||||
The thunk action creator function will have plain action creators for the pending, fulfilled, and rejected cases attached as nested fields.
|
||||
|
||||
The `payloadCreator` function will be called with two arguments:
|
||||
|
||||
- `arg`: a single value, containing the first parameter that was passed to the thunk action creator when it was dispatched.
|
||||
- `thunkAPI`: an object containing all of the parameters that are normally passed to a Redux thunk function, as well as additional options:
|
||||
- `dispatch`: the Redux store dispatch method
|
||||
- `getState`: the Redux store getState method
|
||||
- `extra`: the "extra argument" given to the thunk middleware on setup, if available
|
||||
- `requestId`: a unique string ID value that was automatically generated to identify this request sequence
|
||||
- `signal`: an `AbortController.signal` object that may be used to see if another part of the app logic has marked this request as needing cancellation.
|
||||
- [...]
|
||||
|
||||
The logic in the `payloadCreator` function may use any of these values as needed to calculate the result.
|
||||
|
||||
```js
|
||||
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
const payloadCreator = async (arg, ThunkAPI): Promise<T> => { /* ... */ };
|
||||
const thunk = createAsyncThunk("<action-type>", payloadCreator);
|
||||
|
||||
thunk.pending; // action creator that dispatches an '<action-type>/pending'
|
||||
thunk.fulfilled; // action creator that dispatches an '<action-type>/fulfilled'
|
||||
thunk.rejected; // action creator that dispatches an '<action-type>/rejected'
|
||||
|
||||
const slice = createSlice({
|
||||
name: '<action-name>',
|
||||
initialState,
|
||||
reducers: { /* standard reducer logic, with auto-generated action types per reducer */ },
|
||||
extraReducers: (builder) => {
|
||||
// Add reducers for additional action types here, and handle loading state as needed
|
||||
builder.addCase(thunk.fulfilled, (state, action) => { /* body of the reducer */ })
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
## RTK Query
|
||||
|
||||
RTK Query is provided as an optional addon within the `@reduxjs/toolkit` package.
|
||||
It is purpose-built to solve the use case of data fetching and caching, supplying a compact, but powerful toolset to define an API interface layer got the app.
|
||||
It is intended to simplify common cases for loading data in a web application, eliminating the need to hand-write data fetching & caching logic yourself.
|
||||
|
||||
RTK Query is included within the installation of the core Redux Toolkit package. It is available via either of the two entry points below:
|
||||
|
||||
```cs
|
||||
import { createApi } from '@reduxjs/toolkit/query'
|
||||
|
||||
/* React-specific entry point that automatically generates hooks corresponding to the defined endpoints */
|
||||
import { createApi } from '@reduxjs/toolkit/query/react'
|
||||
```
|
||||
|
||||
RTK Query includes these APIs:
|
||||
|
||||
- [`createApi()`][new_api]: The core of RTK Query's functionality. It allows to define a set of endpoints describe how to retrieve data from a series of endpoints,
|
||||
including configuration of how to fetch and transform that data.
|
||||
- [`fetchBaseQuery()`][fetch_query]: A small wrapper around fetch that aims to simplify requests. Intended as the recommended baseQuery to be used in createApi for the majority of users.
|
||||
- [`<ApiProvider />`][api_provider]: Can be used as a Provider if you do not already have a Redux store.
|
||||
- [`setupListeners()`][setup_listener]: A utility used to enable refetchOnMount and refetchOnReconnect behaviors.
|
||||
|
||||
[new_api]: https://redux-toolkit.js.org/rtk-query/api/createApi
|
||||
[fetch_query]: https://redux-toolkit.js.org/rtk-query/api/fetchBaseQuery
|
||||
[api_provider]: https://redux-toolkit.js.org/rtk-query/api/ApiProvider
|
||||
[setup_listener]: https://redux-toolkit.js.org/rtk-query/api/setupListeners
|
207
javascript/svelte/svelte.md
Normal file
207
javascript/svelte/svelte.md
Normal file
|
@ -0,0 +1,207 @@
|
|||
# [Svelte](https://svelte.dev/docs)
|
||||
|
||||
```sh
|
||||
npx degit sveltejs/template <project name>
|
||||
|
||||
# set project to use typescript
|
||||
node scripts/setupTypeScript.js
|
||||
|
||||
# or using vite
|
||||
npm init vite@latest
|
||||
```
|
||||
|
||||
## App Entry-point
|
||||
|
||||
```js
|
||||
import App from "./App.svelte"; // import the component
|
||||
|
||||
const app = new App({
|
||||
target: document.body,
|
||||
props: {
|
||||
// props passed to the App component
|
||||
},
|
||||
});
|
||||
|
||||
export default app;
|
||||
```
|
||||
|
||||
## Components (`.svelte`)
|
||||
|
||||
### Basic Structure
|
||||
|
||||
```html
|
||||
<!-- code for the component -->
|
||||
<script lang="ts">
|
||||
import { Component } from "Component.svelte";
|
||||
|
||||
export let prop; // make a variable a prop
|
||||
</script>
|
||||
|
||||
<!-- CSS for the component -->
|
||||
<style>
|
||||
/* CSS rules */
|
||||
|
||||
/* target elements outside of the current component */
|
||||
:global(selector) {
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- html of the component -->
|
||||
|
||||
<!-- dynamic expressions -->
|
||||
<div>{variable}</div>
|
||||
|
||||
<!-- nested components -->
|
||||
<Component prop="{value}" />
|
||||
```
|
||||
|
||||
### If-Else
|
||||
|
||||
```js
|
||||
{#if <condition>}
|
||||
// markup here
|
||||
{:else if <condition>}
|
||||
// markup here
|
||||
{:else}
|
||||
// markup here
|
||||
{/if}
|
||||
```
|
||||
|
||||
### Loops
|
||||
|
||||
```js
|
||||
{#each array as item, index} // index is optional
|
||||
// markup here
|
||||
{/each}
|
||||
|
||||
{#each array as item (key)} // use key to determine changes
|
||||
// markup here
|
||||
{/each}
|
||||
```
|
||||
|
||||
### Await Blocks
|
||||
|
||||
```js
|
||||
{#await promise}
|
||||
<p>...waiting</p>
|
||||
{:then number}
|
||||
<p>The number is {number}</p>
|
||||
{:catch error}
|
||||
<p style="color: red">{error.message}</p>
|
||||
{/await}
|
||||
```
|
||||
|
||||
### Event Handling
|
||||
|
||||
The full list of modifiers:
|
||||
|
||||
- `preventDefault` — calls `event.preventDefault()` before running the handler. Useful for client-side form handling, for example.
|
||||
- `stopPropagation` — calls `event.stopPropagation()`, preventing the event reaching the next element
|
||||
- `passive` — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so)
|
||||
- `nonpassive` — explicitly set `passive: false`
|
||||
- `capture` — fires the handler during the capture phase instead of the bubbling phase
|
||||
- `once` — remove the handler after the first time it runs
|
||||
- `self` — only trigger handler if `event.target` is the element itself
|
||||
|
||||
```js
|
||||
<script>
|
||||
const eventHandler = () => {};
|
||||
</script>
|
||||
|
||||
<button on:event={eventHandler}>
|
||||
// or
|
||||
<button on:event={() => eventHandler(args)}>
|
||||
|
||||
<button on:event|modifier={eventHandler}>
|
||||
```
|
||||
|
||||
**NOTE**: It's possible to chain modifiers together, e.g. `on:click|once|capture={...}`.
|
||||
|
||||
## Binding
|
||||
|
||||
```html
|
||||
<script>
|
||||
let name = "Foo";
|
||||
</script>
|
||||
|
||||
<!-- modify value in real time -->
|
||||
<input bind:value="{stringValue}" />
|
||||
<input type="checkbox" bind:checked={boolean}/ >
|
||||
<!-- ... -->
|
||||
```
|
||||
|
||||
### Reactive declarations & Reactive Statements
|
||||
|
||||
Svelte automatically updates the DOM when the component's state changes.
|
||||
Often, some parts of a component's state need to be computed from other parts and recomputed whenever they change.
|
||||
|
||||
For these, Svelte has reactive declarations. They look like this:
|
||||
|
||||
```js
|
||||
let count = 0;
|
||||
$: double = count * 2; // recalculated when count changes
|
||||
// or
|
||||
$: { }
|
||||
$: <expression>
|
||||
```
|
||||
|
||||
## Routing
|
||||
|
||||
[Svelte Routing](https://github.com/EmilTholin/svelte-routing)
|
||||
|
||||
```js
|
||||
<!-- App.svelte -->
|
||||
<script>
|
||||
import { Router, Link, Route } from "svelte-routing";
|
||||
import Home from "./routes/Home.svelte";
|
||||
import About from "./routes/About.svelte";
|
||||
import Blog from "./routes/Blog.svelte";
|
||||
|
||||
export let url = "";
|
||||
</script>
|
||||
|
||||
<Router url="{url}">
|
||||
<nav>
|
||||
<Link to="/">Home</Link>
|
||||
<Link to="about">About</Link>
|
||||
<Link to="blog">Blog</Link>
|
||||
</nav>
|
||||
<div>
|
||||
<Route path="blog/:id" component="{BlogPost}" />
|
||||
<Route path="blog" component="{Blog}" />
|
||||
<Route path="about" component="{About}" />
|
||||
<Route path="/"><Home /></Route>
|
||||
</div>
|
||||
</Router>
|
||||
```
|
||||
|
||||
## Data Stores
|
||||
|
||||
```js
|
||||
// stores.js
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
export const count = writable(0);
|
||||
```
|
||||
|
||||
```html
|
||||
<script>
|
||||
import { onDestroy } from "svelte";
|
||||
import { count } from ".path/to/stores.js";
|
||||
|
||||
const unsubscriber = count.subscribe((value) => {
|
||||
// do stuff on load or value change
|
||||
});
|
||||
|
||||
count.update((n) => n + 1);
|
||||
|
||||
count.set(1);
|
||||
// or
|
||||
$count = 1;
|
||||
|
||||
onDestroy(unsubscriber);
|
||||
</script>
|
||||
|
||||
<!-- use $ to reference a store value -->
|
||||
<p>{$count}</p>
|
||||
```
|
Loading…
Add table
Add a link
Reference in a new issue