How to get dom object of current component in Polymer.js 2.0? - dom

I defined component of polymer.js 2.0.
and inside member function of this component, I would like to get current component content as dom object after dom ready. is this possbile?
How can I get dom object of current component after it attached to document?

Since any Custom Element is an HTML element, this is a reference to the DOM object. Custom Elements created with the Polymer library are no different in this regard.
All the methods and properties of the HTMLElement prototype are available inside member functions of a Polymer Element:
_onClick() {
const span = document.createElement('span');
span.innerText = 'hi there!';
this.appendChild(span);
}
Here is a simple JSFiddle for this example: https://jsfiddle.net/vlukashov/oyr5bpyk/

Related

Aurelia - Accessing ViewModel functions/binding from within Generated DOM elements

I have a section of my view (html) that is generated programmatically by a viewmodel/class. This uses the Aurelia DOM (Aurelia Docs - pal :: Dom) functionality to generate and add the raw HTML elements to the view.
However, I am unable to get events within the generated html to call back to the viewmodel. An example:
let deleteButton = this.dom.createElement("button");
deleteButton.setAttribute("onclick", "cancelCreditNote(`${ row.creditNoteId }`)");
A click on the generated button won't call back to the viewmodel, which does have a cancelCreditNote function. Various other things like deleteButton.setAttribute("click.delegate", "cancelCreditNote('${ row.creditNoteId }')"); do not work either.
Does anyone know how to access a viewmodel class from essentiall 'raw' html in aurelia?
Unfortunately in this instance I cannot use the standard aurelia templating to generate the HTML.
The DOM property on PAL is just an abstraction for the browser's DOM object, create element is likely just calling document.createElement which doesn't afford any Aurelia binding to the created element.
You could try using aurelia.enhance(context, element) which takes an existing DOM element and runs it through the templating engine.
With this method you can also pass a binding context to apply to the element.
In my HTML I use this:
<div id="collapsesidebar" click.delegate="toggleSidebar()">
In my view-model I have this method:
toggleSidebar(){
alert('hi');
}
You could also do this from your view-model with JQuery like this:
attached() {
$('main').on('click', ()=> alert('hi'));
}
The last option is ONLY available áfter the attached() method is triggered: before that the binding needs to do its job and only after that the elements are located inside of the dom.
In other words: this will not work:
activate(){
$('main').on('click', ()=> alert('hi'));
}
because the constructor and the activate method both get fired before the attached method.

Angular2 model-based parent/children form

I'm a newbie with Angular2 (beta1) and I'd like to implement a sort of simple editable grid, built of 2 components. Here I use two fake-data components to keep things simple. They are (see this Plunker: http://plnkr.co/edit/5cZfLTIlhLc82wWV4PQI):
the parent component, named contact. Say it represents a contact with a name.
the child component, named entry. Say it represents an entry for a contact, where each contact can include 0 or more entries. Each entry has an address and a zip code.
I'd like to create a form where the user can edit the contact's properties, and also its children entries: he could add a new entry, delete an existing entry, or edit an existing entry.
To this end, the views for both these components provide a form-based template.
I can think of this data flow:
contact: the user edits the form and then clicks a submit button to save
the whole thing. Thus, I can just have some code handling the submit button
and emitting an event as the component output. The contact has an entries
array property: I can thus use an ngFor directive in its template to render
an entry component for each of them.
entry: the entry has properties addressCtl and zipCtl which represent
the control directives included in the ControlGroup representing the whole
form. Also, I need a couple of properties to be bound as the input of the
component (address and zip), so that in the parent template I can do something like:
<tr *ngFor="#e of entries">
<td><my-entry [address]="e.address" [zip]="e.zip"></my-entry></td>
</tr>
Now, it's not clear to me how to shape the relation between the "model" properties representing the control's input, and the "form" directives properties. I should be able to get the address and zip values from the parent component through the [...] binding, and pass the updated values up through an event fired by the child component (e.g. blur?). Does this make sense in the NG2 world? Anyway, I'm missing a piece here: how can I connect the form controls values to the model properties values? Could anyone make this clearer or point to some good docs?
In fact, using the [...] binding only corresponds to a one-way binding. When the parent property is updated in the parent component, the value is also updated in the child component.
But if you want to update parent attributes from the child, you need to leverage events and #Ouput attribute.
Here is a sample with a labels component:
export class LabelsComponent implements OnInit {
#Input()
labels:string[];
#Output()
labelsChange: EventEmitter;
(...)
removeLabel(label:string) {
var index = this.labels.indexOf(label, 0);
if (index != undefined) {
this.labels.splice(index, 1);
this.labelsChange.emit(this.labels);
}
}
addLabel(label:string) {
this.labels.push(this.labelToAdd);
this.labelsChange.emit(this.labels);
this.labelToAdd = '';
this.addAreaDisplayed = false;
}
}
This way you can leverage two way binding on this component:
<labels [(labels)]="company.labels"></labels>
Hope it answers your question,
Thierry
Just moved the comment to answer...
You can pass the object e, instead of passing string.
i.e
<my-entry [entry] = "e"></my-entry>
then in your my-entry component, use ng-model for each input. so you automatically gets 2 way bindings.

querySelect angular component as MyComponent

I have an angular component
<my-component foo="" bar=""></my-component>
And its corresponding class MyComponent
I use this component in my html
<my-component foo="bar" bar="foo"></my-component>
<my-component foo="baz" bar="qux"></my-component>
<my-component foo="bar" bar="baz"></my-component>
Now i want to querySelect my custom elements and access their attributes directly. I think about something like this:
List<MyComponent> mys = querySelector('my-component');
mys.forEach((my){
print(my.foo);
my.bar = '1234';
});
There are a view problems with that code:
querySelector always returns Element not MyComponent. can i cast Element to MyComponent?
Is MyComponent to <my-component> like DivElement to <div>?
querySelector cannot select custom elements. i could ad a class to every my-component and select it with that class. or is there another way?
I only can access the attributes with my.getAttribute() not with my.foo. I know, this is because my is still a Element not a MyComponent.
This is not officially supported. There was something like ng-element that allowed this as far as I remember but was intended to be only used for unit tests. There were some changes in the last versions but I don't know the current state.
You should pass references using dependency injection, Angular events (explained here How to communicate between Angular DART controllers) or the scope to access other elements.

when the dom is loaded exactly what's going on?

When we say, DOM is loaded , I mean the DOM but not the page.
What happens in the browser! When DOM is loaded? Please can you be more precise.
thank you
"When the DOM is loaded but not the page" doesn't really mean much. As the HTML is loaded, the browser renders it as the static page you see on your screen. The DOM is the representation that allows interaction with those elements.
For example, I can create objects in JavaScript and then manipulate them, but I've only manipulated a simple object. A DOM object, looks like the same object, but it's tied to a correlating [X|XH|H]TML object; so that when I call a method on this object, it didn't just interact with a container of information but its constituent node on the page. Consequently, you can't use a DOM method on an element that hasn't been rendered yet.
Tangible example:
/* Manipulating a standard JavaScript object */
var obj = { firstProp: "InitialValue",
secondProp: "somethingelse",
aMethod: function(){ this.firstProp = "Changed" }
}
console.log(obj.firstProp); // Ouput is "InitialValue"
obj.aMethod();
console.log(obj.firstProp); // Output is "Changed", but nothing is effected other than that value
/* Here is a method called on a DOM element; pretend it's an input/text */
var obj2 = document.getElementById("testId");
obj2.value = "This is your new text box value";
In the second example, you see that I didn't just change an arbitrary object's value. I've change the HTML's rendered representation of that object.
That's the best way I can think to explain it at the moment.

JQuery. Accessing Elements in the DOM below and object

I'm using an API that returns a JQuery Object which is a reference to a DIV container. I know my structure inside of the DIV container. I basically need to read some attributes from the first .
I've tried chaining the standard selectors off of my object but I get an error.
XML filter is applied to non-XML value ({selector:"div.panes > div.slice(0,1)", context:({}), 0:({}), length:1})
[Break on this error] var svideo = $(api.getCurrentPane()).('a').get(0);
Change your code to use .find() when you're going for descendant elements, like this for the DOM element reference directly:
$(api.getCurrentPane()).find('a').get(0)
//or..
$(api.getCurrentPane()).find('a')[0]
or if you want a jQuery object...
$(api.getCurrentPane()).find('a:first')
//or..
$(api.getCurrentPane()).find('a:eq(0)')
//or..
$(api.getCurrentPane()).find('a').eq(0)