should I use attributes or properties to pass data? - polymer

In lit-element, in most of the cases passing data from parent-component to child-component via attributes and via properties result in the same thing.
I wonder in which case I should use attributes while which case properties?

The difference between attributes and properties is that attributes are expressed in the DOM, while properties are not. The element can decide to reflect the properties back to attributes, but that is somewhat orthogonal. Example:
<my-button raised></my-button>
Here, raised is a boolean attribute, and it is convenient to pass data that way because you can do it declaratively in the DOM. <my-button>'s implementation does not have to know whether the attribute or the property was used to pass this data, because attributes get converted to properties automatically (if a property with a matching name was declared).
The following works as well (lit-element specific), but assigns the property directly.
<my-button .raised=true></my-button>
The implementation of my-button can decide if changes to the property get reflected back to the attribute. This is useful if you want to use the attribute, for example, in CSS for styling.
Generally, however, you just assign properties and let the custom element decide whether the property gets reflected back to the attribute. Say you want to control the button programmatically, you would just assign the property
this.button_.raised = true;
instead of writing
this.button_.setAttribute('raised', true);
Note, this always works with custom elements and even a few native elements (e.g., input's value is a property, too). But you can't write:
this.myDiv_.id = 'container';
because <div>s don't have properties, and you have to use setAttribute().

Related

Aurelia ref attribute in child container

I have a parent component where the view model contains a property prop1.
In its view, a custom element has a view-model.ref="prop1".
export class Parent {
public prop1;
}
<template>
<custom-element view-model.ref="prop1"></custom-element>
</template>
This works like a charm and I get a reference to the view model of my custom element in my parent.
Now, I add a child router to parent with a child component. In child's view model, I add a property prop1. and in its view, a custom element has a view-model.ref="prop1". So exactly like I did in parent...
As soon as I navigate to parent/child, the parent's container prop1 stops referencing the custom element of parent and starts referencing the one from child.
If I name the properties differently, there is no problem.
Any idea why this happens? And how could I avoid this behavior without worrying about the naming of the properties?
EDIT
I chanced upon some more information! If the properties are initialized in the view model, I seem to be able to retain the references in the view models. Note that I'm using Typescript so I think the compiled code for an unassigned class property doesn't mention the property at all until it is assigned.
I still don't really understand where the problem comes from exactly...
And I remain with the same problem if I use a view-model.ref directly in the template without mapping it to an explicit property from the view model like this:
<template>
<custom-element view-model.ref="custom"></custom-element>
<custom-element2 opened.call="custom.opened()"></custom-element2>
</template>
when you create a property in a class and don't assign anything to it, babel/typescript will remove that property as if it was not even declared.. because it's really not doing anything.
typescript is interested in your definitions in compile time only.
now that your property in the child is emitted, you have a binding in the child to an undeclared property.
in that case, aurelia creates a property for you and bind to it..
but in your case, aurelia finds this property in the parent scope (just like regular JS scoping rules), and therefor do not create a "new property" in the child scope but rather binds to the parent property.
this is why when you initialize the property in the child (even with undefined) it "works". because you have 2 properties in 2 scopes.
and when you change the name, aurelia will create a new property for you..
and here come another rule - wen aurelia create a property for you - it creates it in the lowest scope available.. in your case - the child scope. and everything works again.
you can notice this behavior a lot with repeate.for, because the repeater creates an invisible scope for each repeate loop..
if you bind anything in the repeate to a property that dont exists, you will have that property in each child, and not once in the parent.

Why doesn't the html 5 attribute not respect a value of false?

In the description from Mozilla it states that the "hidden" attribute on an element is a boolean global attribute. When I use something like:
<div hidden="false">Test</div>
the element remains hidden. It appears that the existence of that attribute regardless of value, hides the content. I would assume that this would work the same as the disabled attribute.
I am asking this question because I am using BootStrap 4 Beta and ReactJs and I want to conditionally show or hide an element using the attribute without having to resort to using jQuery.
When you set a value you actually flag it as true (can't find the reference for it but i read about it somewhere).
With react you do have other options of course:
Use a css class with display:none for example.
Conditionally render the element, it wont be hidden but will be absent.
EDIT
Found the reference :)
A number of attributes in HTML5 are boolean attributes. The presence
of a boolean attribute on an element represents the true value, and
the absence of the attribute represents the false value.
A number of attributes...

Data binding between two Polymer-elements

I have two polymer elements like
<moviegrep-element></moviegrep-element>
<custom-card-element></custom-card-element>
In moviegrep-element I got an array of objects called results. I want to use the results in my custom-card-element. How does it work?
Use Polymers data-binding:
<moviegrep-element results="{{sharedResults}}"></moviegrep-element>
<custom-card-element results="{{sharedResults}}"></custom-card-element>
This assumes that both of your elements publish the results property as an attribute. Changes to the results property in one element are then propagated to the results property in the other element.
This also assumes that your elements are itself inside a Polymer element. Otherwise you need an auto-binding template element

What Gets Added to `document`?

I was working on a page and noticed they had an element bound to document (ex. document.formNameId). I was thinking it must be the JavaScript and not being able to find a place where it was set, I removed all the JavaScript on the page. I still found the element name set on the document.
After playing with it, it seems form elements that have a name attribute set are added to document. Are there any other elements that are by default bound like that?
EDIT:
Upon further inspection, you can even find elements inside that form element by the same API.
So if I do something like this to get an input element: document.formName.inputName
Check this example out.
Yes, these are called (in HTML5) Named Properties
The description in the spec says:
The Document interface supports named properties. The supported
property names at any moment consist of the values of the name content
attributes of all the applet, exposed embed, form, iframe, img, and
exposed object elements in the Document that have non-empty name
content attributes, and the values of the id content attributes of all
the applet and exposed object elements in the Document that have
non-empty id content attributes, and the values of the id content
attributes of all the img elements in the Document that have both
non-empty name content attributes and non-empty id content attributes.
The supported property names must be in tree order, ignoring later
duplicates, with values from id attributes coming before values from
name attributes when the same element contributes both.
So these happens for a number of elements. There is also a description at the above link of how the values of such properties are determined, including how for forms, it becomes the list of controls on the form.
https://developer.mozilla.org/en-US/docs/Web/API/document has a good overview over all properties and methods of the document object.
[obsolete: document.formNameId is missing there and I could not find it on this website, so it seems it is not a default property but was added by a script (a quick google search for "document.formnameid" lists only this stackoverflow question).]

How can I access an element by using its DOM hierarchy(parent element)?

I want to access an element using a DOM hierarchy Node structure, through its parent nodes.I am trying to find the DOM hierarchy through firebug; want something like, <parent_node1>.<child_node1>.<child_node2> (not by document.getElementByID, getElementbyname) to access an element.
I want to automate a scenario like, I have column headers and corresponding values. Want to test, whether the values present under each column header, is correct...
I am thinking of using DOM as a method of automating this case...But, how can I find the DOM hierarchy...?
What I see through Inspect Element in Firebug is something like, list of events, elements and is not looking like a hierarchy node structure...Can somebody help in this regard please?
As discussed, you probably mean the DOM Element properties like element.childNodes, element.firstChild or similar.
Have a look at the DOM Element property reference over at JavaScriptKit, you'll get a good overview there how to access the hierarchy.
var currentTD = document.getElementsByTagName("td")[0];
var currentTable = document.getElementsByTagName("table")[0];
currentTD.parentNode // contains the TR element the TD resides in.
currentTable.childNodes // contains THEAD TBODY and TFOOT if present.
DOM Tables even have more properties like a rows collection and a cells collection.
A reminder of caution: Beware that these collections are live collections, so iterating over them and accessing collection.length in each iteration can be really slow because to get the length, the DOM has to be queried each time.
document.getElementById and document.getElementByTagname are using the DOM. They take an object within the DOM (specifically the document object, though you can also call both of those on elements) and return an object which is a single element or a collection of zero or more elements, respectively. That's a DOM operation. From there you can do other DOM operations on the results like getting children, parents or siblings, changing values etc.
All DOM operations come down to:
Take a starting point. This is often document though it's so often that the first thing we do is call document.getElementById or document.getElementByTagname and then work from the result that we could really consider that the starting point.
Find the element or elements we are interested in, relative to the starting point whether through startingPoint.getElementById* or startingPoing.getElementByTagname perhaps combined with some test (e.g. only working on those with a particular classname, if they have children of particular types, etc.
Read and/or change certain values, add new child nodes and/or delete nodes.
In a case like yours the starting point will be one or more tables found by document.getElementById(someID), document.getElementById(someID).getElementsByTagname('table')[0], or similar. From that table, myTable.getElementsByTagname('th') will get you the column headings. Depending on the structure, and what you are doing with it, you could just select corresponding elements from myTable.getElementsByTagname('td') or go through each row and then work on curRow.getElementsByTagname('td').
You could also just use firstChild, childNodes etc. though it's normally more convenient to have elements you don't care about filtered out by tagname.
*Since there can only be one element with a given id in a document, this will return the same if called on any element higher in the document hierarchy, so we normally just call this on document. It can be useful to call it on an element if we want to do something if the element is a descendant of our current element, and not otherwise.