Manually destroy and reset element? - polymer

Polymer 1.*
I have a custom element that has a form. In addition, there is a few event listeners and custom handlers that I have states for in different parts of the form.
When a user submits the form, I can just do reset() on the form. But this doesn't reset the states inside the handlers I have for my custom logic.
After a user submits the form, I element needs to reset to it's default values. The cleanest way to do this is to destroy the template and re-stamp it. I don't want to have to manually code and reset each object property/variable state.
I can not use <template is="dom-if" if="{{condition}}" reset> because that can only be used in a nested template...which means states/variables/objects persist for the parent template.
Is there a way I can destroy a template and restamp it? Performance hit is not a issue here.

what i suggest you to do is to wrap your form with custom element. so for example you create element called my-form and put iron-form and all inputs inside it. inside your my-form element you will need to propagate events to parent propably, which isn't problem, since there is fire() function you can call in my-form and addEventListener in parent element.
So in my-form you will listening to iron-form onSubmit then call this.fire("formSubmitted"); and in parent element inside (for example) ready function:
this.addEventListener("formSubmitted", function() {
Polymer.dom(this.root).removeChild(this.$$("my-form"));
Polymer.dom(this.root).appendChild(document.createElement("my-form");
}.bind(this));
and that's it. I hope i understand your question right.

Related

polymer - remove tap listener from light dom

i've just started web programming and have a problem with removing a tap listener added with polymer.
My component 'my-button' has a tap listener:
listeners: {
tap: '_onTap'
}
my-buttons can be added to a my-button-group.
<my-button-group>
<my-button></my-button>
<my-button></my-button>
...
</my-button-group>
if a button was added to a my-button-group i want to remove the tap listeners of all buttons in the group.
i've tried to iterate over the groups children, but i can't find the listener in the childrens attributes/properties.
thank you
I assume you are iterating over the children with Polymer.dom(group).functions then call node.unlisten() to remove listener (see https://www.polymer-project.org/1.0/docs/api/Polymer.Base and go to the methods and the api. You can use this.unlisten() if you are working within an element, but any reference to the element will work. Remember that the nodes you are working with are "distrubuted" (ie they come from the content) so you will need to use Polymer.dom(mygroup).getDistributedNodes();

How to access more than 2 DOM elements "The AngularJS way"?

I'm starting to learn angularJS better, and I've noticed that AngularJS tries to make strong emphasis on separating the view from the controller and encapsulation. One example of this is people telling me DOM manipulation should go in directives. I kinda got the hang of it now, and how using link functions that inject the current element allow for great behavior functionality, but this doesn't explain a problem I always encounter.
Example:
I have a sidebar I want to open by clicking a button. There is no way to do this in button's directive link function without using a hard-coded javascript/jquery selector to grab the sidebar, something I've seen very frowned upon in angularJS (hard-coding dom selectors) since it breaks separation of concerns. I guess one way of getting around this is making each element I wish to manipulate an attribute directive and on it's link function, saving a reference it's element property into a dom-factory so that whenever a directive needs to access an element other than itself, it can call the dom-factory which returns the element, even if it knows nothing where it came from. But is this the "Angular way"?
I say this because in my current project I'm using hard-coded selectors which are already a pain to mantain because I'm constantly changing my css. There must be a better way to access multiple DOM elements. Any ideas?
There are a number of ways to approach this.
One approach, is to create a create a sidebar directive that responds to "well-defined" broadcasted messages to open/close the sidebar.
.directive("sidebar", function(){
return {
templateUrl: "sidebar.template.html",
link: function(scope, element){
scope.$root.$on("openSidebar", function(){
// whatever you do to actually show the sidebar DOM content
// e.x. element.show();
});
}
}
});
Then, a button could invoke a function in some controller to open a sidebar:
$scope.openSidebar = function(){
$scope.$root.$emit("openSidebar");
}
Another approach is to use a $sidebar service - this is somewhat similar to how $modal works in angularui-bootstrap, but could be more simplified.
Well, if you have a directive on a button and the element you need is outside the directive, you could pass the class of the element you need to toggle as an attribute
<button my-directive data-toggle-class="sidebar">open</button>
Then in your directive
App.directive('myDirective', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
angular.element('.' + attrs.toggleClass).toggleClass('active');
}
};
}
You won't always have the link element argument match up with what you need to manipulate unfortunately. There are many "angular ways" to solve this though.
You could even do something like:
<div ng-init="isOpen = false" class="sidebar" ng-class="{'active': isOpen}" ng-click="isOpen = !isOpen">
...
</div>
The best way for directive to communicate with each other is through events. It also keeps with the separation of concerns. Your button could $broadcast on the $rootScope so that all scopes hear it. You would emit and event such as sidebar.open. Then the sidebar directive would listen for that event and act upon it.

How can I know that Template Repeat has finished?

Element needs some time for template-repeat to render all content, so paper-spinner is used to notify the user to wait.
How can I know that template-repeat has finished so I can turn off the spinner?
And related question: how can inner element "item-details" be selected? Again, template-repeat has to be finished first.
Here's the code I am using:
<polymer-element name="item-list">
<template>
<paper-spinner active></paper-spinner>
<template id="repeat_items" repeat="{{ item in car.items }}">
<item-details id="item_details" item="{{item}}"></item-details>
</template>....
This is some simulation of the problem: plnkr.co
Edit
links from research:
spinner example
why does onmutation disconnect after first mutation?
polymer-how-to-watch-for-change-in-content-properties
There are component lifecycle hooks.
You are probably looking for domReady.
Called when the element’s initial set of children are guaranteed to exist. This is an appropriate time to poke at the element’s parent or light DOM children. Another use is when you have sibling custom elements (e.g. they’re .innerHTML‘d together, at the same time). Before element A can use B’s API/properties, element B needs to be upgraded. The domReady callback ensures both elements exist.
Polymer('tag-name', {
domReady: function() {
// hide the spinner
// select the first item details element
}
});
As for selecting elements, you can traverse the component's shadow dom like so:
this.shadowRoot.querySelector(selector);
EDIT...
The domReady hook is great if you have all of your data up-front. If you get data asynchronously, then you can use a change watcher.
Here's is a fork of your plunkr that successfully selects the child components after the data changes. Notice the setTimeout(f, 1) that defers selection until after the DOM updates.
carsChanged: function(){
var _this = this;
setTimeout(function(){
console.log(_this.shadowRoot.querySelectorAll('item-details'))
},1)
}
I suggest something like this - http://jsbin.com/bifene/4/edit
Leverages Polymer's onMutation function to watch for changes to a DOM node. Note that it only gets called once so you'll need to re-register it every time you load new items & restart the spinner.

multiple select dropdown with checkbox in flex 4

I am trying to implement multiple select on ComboBox with check boxes in flex 4.1. By default the combo box closes after every select, is there any way to override that default function?
1) // is there any way to override that default function?
In combobox the open/close of the popupList was handled by DropDownController.as in DropDownListBase.as i hope u can override closeDropDown method to prevent close.But ensure you need to handle the close when click outside the combobox.
override public function closeDropDown(commit:Boolean):void
{
// your logic goes here
// call super if needed to close
//super.closeDropDown(commit);
}
For preventing the default behavior You can also use the below methods on close event (or ItemClick event if it has one)
event.preventDefault();
which Cancels an event's default behavior if that behavior can be canceled.
event.stopPropagation();
which Prevents processing of any event listeners in nodes subsequent to the current node in the event flow.
There are lot of flex example out there for combobox with checkbox itemrenderer before u post any question in stackOverflow do a Google search.
I hope this will help you
https://code.google.com/p/combocheck/source/browse/#svn%2Ftrunk
http://www.flexicious.com/home/FlexMultiSelectComboBox

Difference between HTML event and JavaScript events

There are many ways by which we can attach an event on an HTML element.
The first way is: HTML attribute
<div id="foo" onclick="print2()> My event is attached as HTML attribute</div>
The second way is using some library (say jQuery)
<div id="bar"> My event is attached using jQuery </div>
<script>
$("#bar").click(function() {
alert("Hi this is Bar");
}
</script>
I earlier thought that jQuery might be internally converting the event to corresponding HTML attribute but this does not happen. Check this http://jsfiddle.net/blunderboy/wp4RU/3/
I am logging all the attributes of foo and bar and see bar does not have onclick attribute.
Please explain.
There is nothing called HTML Event! The two types of events you have described are, inline events and unobtrusive events, and both are javascript events.
Inline Events
When you declare javascript code on the elements itself, then it becomes an inline event. You have a few common events (as attributes to HTML Elements) like onclick, onkeydown, onkeypress, onkeyup, and all of them start with on. One such example is:
Click Me!
Unobtrusive Events
We need to assign something to be performed when the event is triggered. The = symbol is always used in JavaScript to assign the value on the right to the method or property on the left.
The window is not the only object we can attach events to. We can attach events to any object within the web page provided that we have a way of uniquely identifying that object. One way of identifying an object is by giving it an ID and referencing it by document.getElementById("id_of_the_element").
Lets take the same example.
Click Me!
Instead of the onclick attribute, I have an ID in the same place, which uniquely identifies the HTML element <a>. Now I can get the ID inside javascript this way:
document.getElementById('clickme');
For this, I can attach an event handler, which doesn't differ much from the way we use the attributes. It just doesn't have the on in the front. In our previous example, we used onclick, but now we are just going to use click.
document.getElementById('clickme').click = functionName;
Here, the functionName refers to any javascript's function name, or an anonymous function. So, for the alert, if we create a function named alertme(), we can define this way:
function alertme()
{
alert('You clicked me!');
}
Now to attach the function to the element can be done this way:
document.getElementById('clickme').click = alertme;
Still feeling lazy, you can do it using the anonymous function way, which takes no name:
document.getElementById('clickme').click = function () {
alert('You clicked me!');
}
Hope you understood. :) Let me know for further clarification.