I have been trying create a polymer-element that generates a ul list based on an ajax request and then renders the "li" elements based on templates that can somehow be passsed in.
It's basically an attempt to make a polymer rebuild of the 'select2' library for autocompletion.
So, the base template I have so far looks like this:
<polymer-element name="auto-complete" attributes="url_base item_template">
<aj-ax id="xhr" url="{{url_base}}" params="{}" handle_as="json" on-ajax-response="{{handle_res}}" on-ajax-error="{{handle_err}}"></aj-ax>
<input id="eingabe" type="text" on-keyup="{{process_request}}" on-blur="{{hide_dropdown}}"/>
<div id="dropdown" hidden?="{{hide}}">
<ul>
<template repeat="{{i in items}}">
<li> i.text
<!--
the process_request handler makes the ajax request and sets
the "items" and un-hides the dropdown.
the above works, but I want to make it more generic so that
you can pass in a template that reads the item model such as
<template ref="{{item_template}}" bind></template>
where item_template is the ID of a template in some outside
scope
-->
</li>
</template>
</ul>
</polymer-element >
</div>
I've also tried to make a base auto-complete.html polymer-element and then extend it based on the auto-complete type...but to no avail.
Any thoughts, ideas?
I want to stick to declarative methods if possible and avoid having to build the DOM elements myself with document.createElement
Is that even possible?
thanks!
I've come up with a cool approach to do this actually!
http://jsbin.com/hesejipeha/2/edit
The main idea is that you conditionally render the your template once you've injected any child templates into the shadow DOM (and thus made it possible to call them by ref in scope!)
Related
I have a component (let's call it ListComponent) whose purpose is to edit a list. It allows the user to add, delete, and reorder elements. Its template looks something like this:
<div> <!-- Some Buttons --> </div>
<ul>
<li *ngFor="element in dataArray">
<string-editor [(NgModel)]=element></string-editor>
<!-- More Buttons -->
</li>
</ul>
The <string-editor> is also a custom component with a template that is basically just an input component with a bit of styling. What I want to be able to do is have multiple versions of ListComponent that can handle different types of data (e.g. numbers, custom objects with multiple fields.) To do this, I would like to be able to replace <string-editor> in the template with another component class (like <number-editor> or <my-custom-object-editor>.) They would all support NgModel. I have looked into dynamic component creation, but it appears that there is no way I can use it with *ngFor's change detection.
So, in summary, is there a way to change <string-editor> to another tag programmatically? If not, is there a way that I can use dynamic component creation with *ngFor's change detection?
What you can do is.
Use a ng switch if u can determine what type of component you need to use. Or You can also write a Ng if else
NgSwitch https://angular.io/api/common/NgSwitch
ng if else https://angular.io/api/common/NgIf
I am aware that Polymer does not support data binding on dynamically created elements. Is it possible to extend template class to have lazy template and regenerate bindings on the template.
I have created a Plunker for this where data binding is working with in static content as well within dynamic content.
https://plnkr.co/edit/8HD0gNERiFSl7qNKdJc0?p=info
So in code example, instead of x-content can we have something like
<template is="dom-lazy" partial="templates/partial1.html">
partial1.html
<h3>Dynamic Content</h3>
<span>{{fname}}</span>
<paper-input label="First Name 2" value={{fname}}></paper-input>
So using Polymer.Templatizer behavior and may be using _forwardParentProp: function(prop, value) is it possible to achieve doz-lazy
Say I have two separate lists of polymorphic objects: Shape -> Circle and Shape -> Rectangle. Shape contains the properties "name" and "description", while Circle contains the properties "center" and "radius" and rectangle contains "length" and "width" properties. I'd like to have a single Polymer component, "shape-list", that would be able to handle display of either the list of Circles or list of Rectangles and display the specific properties of each type in the list.
"shape-list"'s template might look something like so:
<template>
<ul>
<template is="dom-repeat" items="[[shapes]]" as="shape">
<li>
<shape-entry shape="[[shape]]">
<!-- The user of shape-list knows whether we want to display
Rectangles or Circles. We want to customize the display
of each shape-entry with information specific to each
shape by using some sort of prototype element supplied
to the shape-list tag. -->
<content select="..."></content>
</shape-entry>
</li>
</template>
</ul>
</template>
And "shape-entry"'s template would look something like so:
<template>
Name: <span>[[shape.name]]</span>
Description: <span>[[shape.description]]</span>
<!-- Ideally we would take the passed-in prototype element and
stamp it out here. -->
<content select="...?"></content>
</template>
Further, we would have templates for "shape-circle" and "shape-rect":
shape-circle:
<template>
Center: <span>[[shape.center]]</span>
Radius: <span>[[shape.radius]]</span>
</template>
shape-rect:
<template>
Length: <span>[[shape.length]]</span>
Width: <span>[[shape.width]]</span>
</template>
The usage would ideally be something like the following:
I can see two ways of accomplishing the above:
Not using "content" tags, but instead setting a property on the shape-list and shape-entry elements to the actual prototype object reference or name of the specific shape, then having some magic JavaScript that creates an instance of that specific shape element based on that property and manually wiring all of the data binding together. This yields additional complexity to assemble the elements and data binding.
Replicate "shape-list" and "shape-entry" into "rect-list", "circle-list" and "rect-entry", "circle-entry", and share styles and behaviors between the subtypes. This results in some code duplication.
Is there a better way of accomplishing the above? I'd (ideally) prefer an entirely declarative approach!
You could have a shape-list component that uses an "if" template to display the proper shape component (rect-entry, circle-entry ). Each shape entry should declare a shared behavior, e.g ShapeBehavior that has all the shared shape behavior to avoid duplicity.
.. inside the dom-repeat
<template is="dom-if" if="{{_isRect(item)}}" >
<rect-entry shape={{item}} ></rect-entry>
</template>
<template is="dom-if" if="{{_isCircle(item)}}" >
<circle-entry shape={{item}} ></circle-entry>
</template>
If you want to dynamically pass the element that should be used , then a programatically solution is needed.
I would like to bind attr and attr1 in the following example. These two parameters do not depend on data (other attributes do). When using the binding this way, there is only one shared data object between all 'rows'. I want only the two components of one iteration to be bound together.
<template repeat"{{data in dataList}}">
<component1 attr="{{binding}}" />
<component2 attr2="{{binding}}" />
</template>
My first idea was to bind the attributes to an variable of the data object:
<template repeat"{{data in dataList}}">
<component1 attr="{{data.binding}}" />
<component2 attr2="{{data.binding}}" />
</template>
This solution on the other hand is really ugly, because the model object get's view-only data attached. Because the model lives normally longer than the components, this could cause a huge overhead. Another problem is serialization, which could fail because of the attached data.
Is there any elegant solution? The only one I imagined so far is to wrap the data objects before iterating over the data set. This approach on the other hand would probably make problems with model updates...
Naive thought: Shouldn't be the scope of a variable that is only used inside of a template restricted to this template? In the special case of the repeat template furthermore to one iteration?
You might type-suggest your binding variable being an Object and use it like:
<polymer-element name="my-element" attributes="dataList">
<template>
<ul>
<template repeat="{{d in dataList}}">
<li>
{{d}} ⇒ {{binding[d]}} <!-- Since type-suggested, it works -->
</li>
</template>
</ul>
</template>
<script>
Polymer({
dataList: ['navy', 'maroon'],
binding: {} /* it’s necessary to type-suggest var for Polymer */
});
</script>
</polymer-element>
Please be aware that the snippet above expects different items in dataList. Live preview: http://plnkr.co/edit/ez36BVUPCKW8xRSkGxOM?p=preview
Naive thought: Shouldn't be the scope of a variable that is only used inside of a template restricted to this template? In the special case of the repeat template furthermore to one iteration?
This sounds impossible for me, because (besides that this will overcomplicate the implementation) sometimes one wants to bind the variable in nested template:
<template repeat="{{a in lst}}">
{{bound_here}}
<template id="nested">
{{bound_here}}
...
With what you suggested the binding above becomes impossible.
I am working on converting a html to angular js and one of the issue i have is, a button on the page uses ID and based of that id there is a div class that runs set of texts to be displayed accordingly.
Code that we have is something like this.
Continue
From the HTML page when the user clicks on the button continue... below code will be executed.
<div class="ContinueClicked">
text.......
</div>
I am trying to figure out a way to see how i can make it work with angular js. So when the user is clicking on the continue button, the page should display the content in div continueClicked. Should i be using any directive here? please help.
You have to adhere to AngularJS principles and conventions. Angular uses Directives for most of the DOM transformations, and Bindings for constant DOM and Model updates (two-way data bindings.)
In your case scenario you might want to have the following DOM elements (inside a Controller inside an ng-app Module, see AngularJS docs):
<!-- The button with the event handler as ng-click directive -->
<button ng-click="isContinue = true">Show continue content</button>
<!-- The content wrap with ng-show directive -->
<div class="ContinueClicked" ng-init="isContinue = false" ng-show="isContinue">
My content to be shown
</div>
You can also read and practice basic concepts following the Angular Tutorial.