test-element.html
house:{ type: String, notify: true}
A.html
<test-element house="my-house"></test-element>
B.html
<test-element house="{{house}}"></test-element>
<div>{{house}}</div>
Why <div>{{house}}</div> is not my-house?
Custom elements are no singletons! Every instance of your Component has its own context. If you want it to behave like a singleton you need to implement redux or use localStorage to store the information
It's because both the test-element are different instantiations. One in A.html is not the same element as one in B.html, even though they have same definition.
In terms of javascript, you can compare it to declaring calling same function twice:
function a(prop1) {
console.log(prop1);
}
a(1) //logs 1
a() //logs undefined
Or if you want to compare it to HTML you can take example of any element (let's say input)
<input id="ip1" value="test">
<input id="ip2">
Now, if you check value for ip2 it will not be test as it is a new instantiation. Same thing happens for custom-elements also.
Related
I have multiple elements on a page that are triggering a load of select2 to the element. I'm trying to conditionally check if the element has a certain class, and if so add the tag option; otherwise do not. I thought something like this would work, but it's not:
$('.element_to_add_select_two_on').select2({
tags:function(element) {
return (element.className === 'classname_i_am_targeting');
},
});
What am I missing here? I'm subjecting myself to the following buffoonery to get this to target and load:
$('.element_to_add_select_two_on').each((index,element) => {
let showTags = false;
if ($(element).attr('class').split(' ').includes('classname_i_am_targeting')) {
showTags = true;
}
$(element).select2({
tags:showTags,
});
});
There are a few problems with your first attempt. First, you are defining tags as a function when what you want is the result of the function, since tags needs to be defined as a boolean true or false. The other is that inside your .select2() call, you do not have access to the calling element $('.element_to_add_select_two_on') in the way that you think. It isn't an event that you are listening on, it's a function call that wants an object passed with its configuration.
You conveyed that your second method works, but it can be simplified with the jQuery hasClass() function:
$('.element_to_add_select_two_on').each((index, element) => {
$(element).select2({
tags: $(element).hasClass('classname_i_am_targeting'),
});
});
There is a much simpler way to do all of this, however, and it is much more flexible and already built into select2 via the way of data-* attributes (note, you need jQuery > 1.x). You can simply add data-tags="true" to any of your select elements with which you want tags enabled. These will override any configuration options used when initializing select2 as well as any defaults:
<select data-tags="true">
...
</select>
I'm wondering, is there a possibility to have databindings "out of" a template? Say I have a <template/>-Tag somewhere which I put into the slot of a different component - that component stamps it to its context. Then I want to bind data from the root element to the <template/>-Tag. Also, event bindings (on-x-changed) don't work, because you can't assign a function which is defined in the hosting component. Any ideas?
Example:
... host
{{boundData}}
<binding-component>
<template>
{{boundData}}
</template>
</binding-component>
I don't see changes when I observe boundData in the hosting component. Is there a way to get around this? Or is firing a custom event my only chance?
If you are looking for binding a property outside of polymer something like from index.html you may bind value with element. an example ; index.html
<dom-bind>
<template>
<binding-component bound-data="{{boundData}}"></binding-component>
</template>
</dom-bind>
<script>
// set a value a string, Number or Object etc.
// Optionally wrap this code into a listener ie;
// window.addEventListener('load', e=> { ...below code ... })
var boundData= document.querySelector('dom-bind');
boundData = {} //
</script>
Now in your binding-component element has a property as boundData
hope its helps or provide more code to understand better.
I've made it work the way dom-if does it, too. Like in dom-if (reference), I'm creating a Templatize-instance which then uses forwardHostProp to handle the "inside"-properties
this.__ctor = Templatize.templatize(template, this, {
mutableData: true,
forwardHostProp(prop, value) {
// handling item updates, item being the only property
// from within the binding component
// everything else is automatically bound by templatize
this.set(prop, value);
this.update(this.item);
},
});
this.__instance = new this.__ctor();
this.root.appendChild(this.__instance.root);
This all happens in connectedCallback.
Because the Templatize-instance is passed this, it's bound to the current context as well.
Good luck!
I need to know if there is a way to create HTML local variables programmatically.
I am developing a web app where I have an NgFor loop and I want to be able to assign a local variable to each sub element created by the NgFor.
ie :
<div *ngFor="#elt of eltList" >
<span #setLocalVariable(elt.title)></span>
</div>
setLocalVariable(_title : string){
let var = do some stuff to _title;
return var;
}
The exemple above shows you what I am trying to accomplish and obviously does not work.
Is there a way to achieve this ?
Thank you in advance.
Edit:
After seeing the answers I got (and i thank everyone who took the time to read my question and tried to answer it) i'll explain a bit more why i want it that way.
I will be using : loadIntoLocation() from the DynamicComponentLoader.
That function got as a 3rd parameter a string that refers to an anchors (ie : #test in an html element). Thats why i need to create those local variables with a name equal to the one of my elt.title.
I think local variables (defined with the # character) don't apply for your use case.
In fact, when you define a local variable on an HTML element it corresponds to the component if any. When there is no component on the element, the variable refers to the element itself.
Specifying a value for a local variable allows you to select a specific directive associated with the current element. For example:
<input #name="ngForm" ngControl="name" [(ngModel)]="company.name"/>
will set the instance of the ngForm directive associated with the current in the name variable.
So local variables don't target what you want, i.e. setting a value created for the current element of a loop.
If you try to do something like that:
<div *ngFor="#elt of eltList" >
<span #localVariable="elt.title"></span>
{{localVariable}}
</div>
You will have this following error:
Error: Template parse errors:
There is no directive with "exportAs" set to "elt.title" ("
<div *ngFor="#elt of eltList" >
<span [ERROR ->]#localVariable="elt.title"></span>
{{localVariable}}
</div>
"): AppComponent#2:10
Angular2 actually looks for a directive matching the provided name elt.title here)... See this plunkr to reproduce the error: https://plnkr.co/edit/qcMGr9FS7yQD8LbX18uY?p=preview
See this link: http://victorsavkin.com/post/119943127151/angular-2-template-syntax, section "Local variables" for more details.
In addition to the current element of the iteration, ngForm only provides a set of exported values that can be aliased to local variables: index, last, even and odd.
See this link: https://angular.io/docs/ts/latest/api/common/NgFor-directive.html
What you could do is to create a sub component to display elements in the loop. It will accept the current element as parameter and create your "local variable" as attribute of the component. You will be able then to use this attribute in the template of the component so it will be created once per element in the loop. Here is a sample:
#Component({
selector: 'elt',
template: `
<div>{{attr}}</div>
`
})
export class ElementComponent {
#Input() element;
constructor() {
// Your old "localVariable"
this.attr = createAttribute(element.title);
}
createAttribute(_title:string) {
// Do some processing
return somethingFromTitle;
}
}
and the way to use it:
<div *ngFor="#elt of eltList" >
<elt [element]="elt"></elt>
</div>
Edit
After your comment, I think that you try the approach described in this answer. Here are more details: create dynamic anchorName/Components with ComponentResolver and ngFor in Angular2.
Hope it helps you,
Thierry
You could stick it into the template interpolation since it handles expressions.
<div *ngFor="#elt of eltList" >
<span>{{setLocalVariable(#elt)}}</span>
</div>
setLocalVariable(_title : string){
let var = do some stuff to _title;
return var;
}
How can I trigger a refresh of the template if a member of a data-bound complex object changes?
In the template:
<other-component data="{{complexObject}}"></other-object>
In the component:
_onChange: function(newData) {
//callback from some event-system
this.set("complexObject", newData);
}
The _onChange-Method is triggered when the complexObject is changed, but newData is always a reference to the same object, just members of this object changed - because of this, polymer doesn't update the view and doesn't pass the data down to other-component.
Is there a way to let polymer know that there is indeed some new data and it has to re-evaluate the template? It is working if I create a shallow clone of newData, but that seems like a hack and could hurt performance for big objects.
I can't use the set method to change the properties of the object via the path because the change happens outside of polymer-elements and I can't control it.
Call render()
this.$.yourTemplateID.render();
Here is one working example where sibling elements are interchanging data between each other: Plunk.
Docs: https://www.polymer-project.org/1.0/docs/devguide/data-binding.html#array-binding
<template>
<button on-tap="btnTapped">change Emploees from Second</button>
second: empl: <span>{{empl.employees.0.firstName}}</span>
</template>
...
<script>
btnTapped: function () {
console.log('Second: btnTapped');
//Propagate array subproperty
this.set('empl.employees.0.firstName', 'Test');
console.log(this.empl.employees[0].firstName);
//Object set
this.set('temp.firstName', 'Test');
}
</script>
this.complexObject = _.clone(this.complexObject)
cloning & reassigning might solve this problem`
how can mootools 1.11 determine if a div contains any checked check boxes?
tried all kinds of variations using $ $$ $E $ES getElements and css selectors, its just not returning true if this div contains no tick boxes
var ticked = $(sId).getElements('[checked=checked]');
if($chk(ticked)){alert('yo');}else{unticked = true;}
"checked" is a dynamically assigned DOM property (which is a boolean), and accessing the attribute only returns the value that was there when the page loaded (or the value you placed when using setAttribute).
Also, as MooTools 1.11 does not have complex selectors (attributes can not be filtered directly within $$) and the filterByAttribute function only accepts direct string comparison, this is your only (and best!) option:
$(sId).getElements('input').filter(function(input) {
return /radio|checkbox/.test(input.getAttribute('type')) && input.checked;
})
note: I added radio just for completeness, the filter loop would have to be run anyways to verify the checked status.
If you want to simplify the process and be able to reuse the code (the MooTools way), you can also mix-in the checked filter into Elements like this:
Element.extend({
getCheckedInputs: function() {
return this.getElements('input').filter(function(input) {
return /radio|checkbox/.test(input.getAttribute('type')) && input.checked;
});
}
});
and then your selection call is reduced to:
$(sID).getCheckedInputs();
From The Documentation:
$(sId).getElements("input:checked");
for 1.1
console.log( $('id').getProperty('checked') );