Document Object Model (DOM)
DOM
Objetivos:
- Entender el DOM y herencia de los nodes
- Trabajar con varios node types
Javascript & DOM
Javascript & DOM (codepen)
- En páginas HTML, "document element" es siempre "<html> element"
Javascript & DOM (codepen)
- En páginas HTML, "document element" es siempre "<html> element"
- Cada pieza está representada por un "node" de hasta 12 tipos diferentes.
Node Type: someNode.nodeType
- Node.ELEMENT_NODE (1)
- Node.ATTRIBUTE_NODE (2)
- Node.TEXT_NODE (3)
- Node.CDATA_SECTION_NODE (4)
- Node.ENTITY_REFERENCE_NODE (5)
- Node.ENTITY_NODE (6)
- Node.PROCESSING_INSTRUCTION_NODE (7)
- Node.COMMENT_NODE (8)
- Node.DOCUMENT_NODE (9)
- Node.DOCUMENT_TYPE_NODE (10)
- Node.DOCUMENT_FRAGMENT_NODE (11)
- Node.NOTATION_NODE (12)
- if (someNode.nodeType == 1) { value = someNode.nodeName} // será el nombre del TAG
- if (someNode.nodeType == 1) {var tipoNode = someNode.attributes[0].nodeType} // tipoNode = 2
Node Relationships
- Todos los nodos en un documento tienen relaciones sobre otros nodos.
- Cada nodo tiene la propiedad childNodes que contiene una NodeList.
- es un array-like object, es decir, una colección de nodos como los devueltos por someNode.childNodes ó document.querySelectorAll () ...
- Aunque no es un array soporta NodeList.foreach
- var firstChild = someNode.childNodes [0] ;
- var secondChild = nodeNode.childNodes.item(1) ; // otro tipo de acceso
- var count = someNode.childNodes.length;
- someNode.lastChild == someNode.childNodes[someNode.childNodes.length-1 ]. // true
- someNode.hasChildNodes() : indica si el nodo tiene uno o más hijos
- No todos los node Types pueden tener childNodes (ej: Node.ATTRIBUTE_NODE)
Manipulating Nodes
- let returnedNode = someNode.appendChild( newNode ) ;
- alert( returnedNode == newNode ) ; // true
- alert( someNode.lastChild == newNode ) ; // true
- let returnedNode = someNode.appendChild( someNode.firstChild ) ; Asumimos varios hijos de someNode
- alert( returnedNode == someNode.firstChild ) ; // false
- alert( returnedNode == someNode.lastChild) ; // true
- let returnedNode = someNode.insertBefore( newNode, null ) ; insert como last child
- alert( newNode == someNode.lastChild ) ; // true
- let returnedNode = someNode.insertBefore( newNode, someNode.firstChild) ; insert com new first child
- alert( returnedNode == newNode) ; / true
- alert( newNode == someNode.firstChild) ; // true
- let returnedNode = someNode.insertBefore( newNode, someNode.lastChild) ;
- alert( newNode == someNode.childNodes[ someNode.childNodes.length -2 ]) ; // true
- let returnedNode = someNode.replaceChild( newNode, someNode.firstChild); // replace first child. El nodo reemplazado sigue pertenciendo al document, pero sin ninguna referencia hacia él.
- let returnedNode = someNode.replaceChild( newNode, someNode.lastChild); // replace last child
- let formerFirstChild = someNode.removeChild( someNode.firstChild ) ; // remove first child. El nodo eliminado sigue pertenciendo al document, pero sin ninguna referencia hacia él.
- let deepList = someNode.cloneNode( true ) ; clona el árbol entero someNode. El nodo clonado sigue pertenciendo al document, pero sin ningún padre asignado.
- alert( deepList.childNodes.length) ; // > 0
- let shallowList = someNode.cloneNode( false ) ; clona solo el nodo inicial, nó sus hijos
- alert( shallowList.childNodes.length) ; // = 0
- isEqualNode(): Un nodo A es igual a un nodo B si se cumplen todas las condiciones siguientes: el valor del atributo nodeType de A y B es idéntico. ... Cada hijo de A es igual al hijo de B en el mismo índice.
- let div1 = document.createElement("div");
- div1.setAttribute("class", "box");
- let div2 = document.createElement("div");
- div2.setAttribute("class", "box");
- alert( div1.isEqualNode(div2) ); // true
- Ejemplo:
Document Type
- Javascript representa document nodes vía Document type.
- En los navegadores the document object es una instancia de HTMLDocument que a su vez hereda de la clase Document
- Características
- document.nodeType es 9
- document.nodeName es #document
- document.nodeValue es null
- document.parentNode es null
- ownerDocument es null
- Child nodes puede tener:
- DocumentType (max 1)
- Element (max 1)
- ProcessingInstruction
- Comment
- document.childNodes
- NodeList (2)
- 0 : <!DOCTYPE html> [object DocumentType]
- 1 : <html ...> ..... </html> [object HTMLHtmlElement]
Document Children
- document.documentElement === document.childNodes[1] ; // true
- document.documentElement === document.firstChild ; // true
- document.body ; // <body ...> ... </body>
- document.doctype === document.childNodes[0] ; // true
Document Information
- document.title
- document.URL
- document.domain
- document.referrer
Locating Elements
- document.getElementById("myDiv")
- document.getElementsByTagName("img") ; retorna un [object HTMLCollection]
- document.getElementsByTagName("img").length ; num. etiquetas img encontradas
- document.getElementsByTagName("img")[0].src
- document.getElementsByTagName("img").item(0).src
- document.getElementsByTagName("img").namedItem("myImage")
- document.getElementsByTagName("img")["myImage"]
- document.getElementsByName("color") retorna un [object HTMLCollection]
Special Collections
- document.anchors Contiene todos las <a> elementos con el atributo name
- document.applets. deprecated
- document.forms. Contiene todos las <form> elementos
- document.images. Contiene todos las <img> elementos
- document.links. Contiene todos las <a> elementos con el atributo href
Element Type
- Es el elemento más utilizado.
- Características:
- nodeType es 1
- nodeName es el tag name del elemento
- nodeValue es null
- parentNode puede ser un documento o elemento
- Child nodes puede ser: Element, Text, Comment, ProcessingInstruction, CDATASection,o EntityReference.
- El nombre de un tag del elemento es accesible vía la propiedad nodeName o tagName
- let div = document.getElementById("myDiv")
- alert(div.tagName); // DIV
- alert(div.tagName == div.nodeName) ; // true
HTML Elements
- Todos los HTML elements son representados por el HTMLElement type
- HTMLElement hereda de Element y añade algunas propiedades.
- id - único identificador para el elemento en el documento
- title
- lang
- dir
- className - equivalente de class attribute
- Ejemplo: elemento.id, elemento.title, etc....
Getting Attributes
- Cada elemento puede tener cero o más atributos
- Un elemento tiene la propiedad attributes que es una colección NamedNodeMaps y cada uno de sus elementos es un nodo tipo atributo Node.ATTRIBUTE_NODE (2)
- En el apartado anterior hemos visto que hay unas propiedades que pueden recuperarse con: elemento.id, elemento.title, etc...
- Custom Attributes no puede recuperarse con elemento.customAttribute. Se hace con getAttribute()
- Los siguientes métodos trabajan con los atributos
- getAttribute()
- setAttribute()
- removeAttribute()
- Ej: <div id="myDiv" class="bd" title="Body Text" mySpecialAttribute="enric"></div>
- var div = document.getElementById("myDiv");
- alert(div.getAttribute("id")) ; // "myDiv"
- alert(div.getAttribute("class")) ; // "bd"
- alert(div.getAttribute("title")) ; // "Body Text"
- alert(div.getAttribute("mySpecialAttribute")) ; // "enric"
- Dos tipos de atributos tienen la property name que no mapea directamente el mismo valor retornado por getAttribute().
- style
- Si accedemos a style con getAttribute(), el style atributo contiene CSS texto
- Si accedemos con la style propiedad retorna un objeto.
- event-handler attributes
Setting Attributes
- Crea o reemplaza un atributo.
- Trabaja de la misma manera HTML attributes y Custom attributes
- Ej: myElement.setAttribute("title", "nuevo titulo")
Remove Attributes
- myElement.removeAttribute("nombre_atributo")
Attributes property
- Elment Type es el único tipo de nodo que utiliza attributes property.
- Attributes property contiene un NameNodeMap que es una "live collection" similar a NodeList.
- Cada atributo de un elemento es representado por un attr node y almacenado en NameNodeMap object.
- NameNodeMap object tiene los siguientes métodos:
- getNamedItem(name)
- removeNamedItem(name)
- let oldAttr = element.attributes.removeNamedItem("id")
- setNamedItem(node)
- element.attributes.setNamedItem(newAttr). Poco utilizado.
- item(pos)
- Cada nodo de attributes property tiene:
- nodeName es el nombre del atributo
- let id = element.attributes.getNamedItem("id").nodeName
- nodeValue es el valor del atributo
- let value_id = element.attributes.getNamedItem("id").nodeValue
- Shorthand notation
- let id = element.attributes["id"].nodeName
- let value_id = element.attributes["id"].nodeValue
- element.attributes["id"].nodeValues = "someOtherId"
- Por comodidad se utilizan más
- getAttribute()
- removeAttribute()
- setAttribute()
- Ejemplo iteración sobre los atributos de un elemento
Creating Elements
- Nuevos elementos se pueden crear con document.createElement(nomEtiquetaTagElement)
- let div = document.createElement("div")
- Al crearlo se actiuliza su ownerDocument property
- No surge efecto hasta que el element creado se añade con
- appendChild()
- insertBefore()
- replaceChild()
- Ejemplo crear elemento
Element Children
- Los elementos pueden tener hijos
- childNodes property contiene todos los hijos
- Al iterar la propiedad childNodes es conveniente tratar solo los elementos tipo Node.ELEMENT_NODE (1)
Text Type
- Text nodes son representados por Text type y contiene texto plano que es interpretado literalmente y puede contener escaped HTML caracteres pero no HTML code.
- Características:
- nodeType es 3
- nodeName es "#text"
- nodeValue es el texto del nodo
- parentNode es un elemento
- Child nodes no está soportado
- El texto contenido puede se accedido por:
- nodeValue property
- data property
- Métodos para text nodes
- appendData(text) Añade texto al final del nodo
- deleteData(offset, count) Elimina count number caracteres a partir de la posición offset
- insertData(offset, text) Inserta text a partir de la posición offset
- replaceData(offset, count, text) Reemplaza el texto a partir de la posición offset
- splitText(offset) Divide el texto del nodo en dos text nodes separados por la posición de offset
- substringData(offset, count) Extrae un string del texto a partir de offset hasta offset + count
- nodeValues.lenght
- data.length
- Ejemplo-1
- Ejemplo-2
Creating Text Nodes
- document.createTextNode() Crea un nuevo test nodes
- Ejemplo-1:
- Ejemplo-2 con dos TextNode:
Normalizing Text Nodes
- Text nodes hermanos pueden llevar a confusión en el DOM
- El método normalize() fusiona los text nodes en uno.
- Ejemplo:
Splitting Text Nodes
- splitText() es el método opuesto a normalize()
- Ejemplo
Comment Type
- Comment Type representa los comentarios en el DOM
- Características del comment node
- nodeType es 8
- nodeName es "#comment"
- nodeValue es el contenido del comentario
- parentNode es un Document o Element
- Child nodes no está soportado
- Ejemplo
CDATASection Type
- CDATASection es específico para XML y está representado por CDATASection type que hereda de textType
- Características
- nodeType es 4
- nodeName es "#cdaa-section"
- nodeValue es el contenido de CDATA section
- parentNode es un Document o Element
- Child nodes no está soportado
DocumentType Type
- DocumentType object contiene toda la información del document doctype
- Características:
- nodeType es 10
- nodeName es el nombre del doctype
- nodeValue es null
- parentNode es un Document
- Child nodes no está soportado
DocumentFragment Type
- Son Nodos del DOM que nunca forman parte del DOM tree.
- Características:
- nodeType es 11
- nodeName es "#document-fragment"
- nodeValue es null
- parentNode es null
- Child nodes puede ser: Element, ProcessingInstruction, Comment, Text, CDATASection o EntityReference
- El caso de uso mas común es crear un document fragment, agregar elementos al document fragment y luego agregar el document fragment al DOM tree.
- Dado que el document fragment es generado en memoria y no como parte del DOM tree, agregar elementos al mismo no castiga al navegador porque no lo renderiza.
- document.createDocumentFragment() crea un fragment node
- Es adecuado para crear listas
- Ejemplo
Attr Type
- Element attributes son representados por el Attr type en el DOM.
- Técnicamente, attributes son nodos que existen en attributes property de un elemento.
- Características
- nodeType es 11
- nodeName es el attribute name
- nodeValue es el attribute value
- parentNode es null
- Child nodes puede ser Text o EntityReference en XML
- Aunque son nodos, attributes no son considerados parte del DOM document tree
- Attributes nodes son raramente reverenciados directamente.
- Generalmente se usan más: getAttribute(), setAttribute() y removeAttribute()
- Hay tres propiedades en un Attr object
- name: attribute name (igual que nodeName)
- value: attribute value (igual que nodeValue)
- specified: es un booleano que indica si el atributo fue especificado en el código o és su valor por defecto
- document.createAttribute() crea un nuevo node attribute
- Ejemplo:
Dynamic Scripts
- Para crear: <script type="text/javascript" src="client.js"></script>
- let script = document.createElement("script");
- script.type = "text/javascript";
- script.src = "client.js";
- document.body.appendChild(script);
- Ejemplo-1:
- Ejemplo-2:
Dynamic Styles
- Para crear: <link rel=stylesheet" type="text/css" href="styles.css">
- let link = document.createElement("link");
- link.rel = "stylesheet";
- link.type = "text/css";
- link.href = "styles.css";
- let head = document.getElementByTagname("head") [0];
- head.appendChild(link);
- Ejemplo-1:
- Ejemplo-2:
Using NodeLists
- Entender NodeList y sus parientes NamedNodeMap y HTMCollection es importante.
- Si iteramos un NodeList para insertar, debemos ir con cuidado para no crear un infinite loop
- Ejemplo: Mal, se crea un infinite loop porque length va aumentando a medida que vamos agregando divs. Recordar que NodeList es un live collection y cada vez que se modifica se renderiza todo de nuevo.
- let divs = document.getElementsByTagName("div");
- let i;
- let div;
- for ( i=0; i < divs.length; i++) {
- div = document.createElment("div");
- document.body.appendChild(div);
- }
- Ejemplo: Bien, se crea una variable len con el valor
- let divs = document.getElementsByTagName("div");
- let I;
- let len;
- let div;
- for ( i=0; len=divs.length; i++) {
- div = document.createElment("div");
- document.body.appendChild(div);
- }
SUMMARY
- Document Object Model DOM Se compone de una serie de tipos de nodos.
- El tipo de nodo base es nodo, que es una representación abstracta de una parte individual de un documento. Todos los otros tipos heredan de Node.
- Document type representa un documento completo y es el nodo raíz de una jerarquía.
- En javascript, Document object es una instancia de Document, que permite la consulta y recuperación de nodos de varias maneras diferentes.
- Un element node representa todos los elementos HTML o XML en un documento y se puede utilizar para manipular sus contenidos y atributos.
- Existen otros node types para text contents, comments, document types, sección CDATA y documents fragments.
- La manipulación del DOM es la mas cara operación en rendimiento que se puede hacer en javascript cuando manipulamos NodeList
- Por esto es importante limitar al máximo el número de manipulaciones del DOM
- El tipo de nodo base es nodo, que es una representación abstracta de una parte individual de un documento. Todos los otros tipos heredan de Node.
- Document type representa un documento completo y es el nodo raíz de una jerarquía.
- En javascript, Document object es una instancia de Document, que permite la consulta y recuperación de nodos de varias maneras diferentes.
- Un element node representa todos los elementos HTML o XML en un documento y se puede utilizar para manipular sus contenidos y atributos.
- Existen otros node types para text contents, comments, document types, sección CDATA y documents fragments.