Polymer, evaluate element based off object - javascript

I am using the tile example from polymers neon elements - and I am trying to make each expanded tile unique. My first try on how to do this was to pass a string in with the grid items like
{
value: 1,
color: 'blue',
template: 'slide-1'
}
And have that element be evaluated when rendered in a new element something like this. (this is the card template itself)
<template>
<div id="fixed" class$="[[_computeFixedBackgroundClass(color)]]"></div>
<div id="card" class$="[[_computeCardClass(color)]]">
<[[item.template]]></[[item.template]]>
</div>
This does not work - however I am wondering if there is some way to do this so I can load custom elements for the content of each card. For reference -https://elements.polymer-project.org/elements/neon-animation?view=demo:demo/index.html&active=neon-animated-pages , it is the grid example and I am trying to replace the content of each card once it is clicked on ( the fullsize-page-with-card.html, here is all the html for it - https://github.com/PolymerElements/neon-animation/tree/master/demo/grid ). Is this the wrong way of approaching this? Or maybe I have some syntax wrong here. Thanks!
Edit : OK, So I can send it through if i add it to the click to open the card like so
scope._onTileClick = function(event) {
this.$['fullsize-card'].color = event.detail.data.color;
this.$['fullsize-card'].template = event.detail.data.template;
this.$.pages.selected = 1;
};
and in the card's properties like so
template: {
type: String
},
So I can then evaluate it as [[template]] , however - the question still remains how to call a custom element (dynamically) using this string. I could pass a couple of properties and fill in a card or form so they are unique, but i think I would have much more creative freedom if I could call custom elements inside each card.

I have an element that allows referenced templates. There are a couple of others other there, but this one also allows data bindings to work: https://github.com/Trakkasure/dom-bindref

Related

Creating dynamic divs

Trying to make a dynamic div but i don't know how. Wrote a solidity smart contract that accepts an array of struct. In the smart contract i can use a get function to display the data inside. Data in the array is treated like a history, it consists of amount (making a crowdfund site), date, currency used, etc. Since the get function in the smart contract can only extract one part of the array, i thought of putting the get function into the while loop and extract the whole history array..
<div id=set>
<a>value1</a>
<a>value2</a>
</div>
I'm trying to dynamically create another div with the same amount of < a > in the div. If i had 10 sets of data to display in that div, i wish to create only 10 sets of that div. Can createElement() be used to do that? Couldn't find any solution that works. Totally have no idea on how to create it. Can someone please help.
Would it be rational to extract the data from the array using a while loop and putting it in a div to display or would it use too much gas for this to work?
I don't get why would you want to do this, but you can do like this:
$('#set a').each(function(){
$('#set').after( "<div></div>");
});
It selects all of the <a>...</a> inside the <div id="set">...</div> element, and for each one of those inserts a <div></div> element. It inserts the element right next to #set but you can change that to any other element you could select.
I'm supplying jQuery code since you tagged the question as jQuery.
Hope it helps,
You can get the number of anchor tags by using this function getElementsByTagName('a').length from the hosting div. Then use that number to create new divs. This solution is done using vanilla JS.
function createDynamicDivs(){
var newDiv = document.createElement("div");
var noOfAnchors = document.getElementById('set').getElementsByTagName('a').length;
for(var i=0;i<noOfAnchors;i++){
var newContent = document.createElement("a");
newContent.textContent= "Test ";
newDiv.appendChild(newContent);
}
document.getElementById('new').appendChild(newDiv);
}
<div id=set>
<a>value1</a>
<a>value2</a>
</div>
<div id="new"></div>
<button onclick="createDynamicDivs()">Generate</button>

Swapping BODY content while keeping state

Dynamically swapping BODY content using jQuery html function works as expected with 'static' content.
But if forms are being used, current state of inputs is lost.
The jQuery detach function, which should keep page state, seems to be blanking out the whole page.
The following code is the initial idea using jQuery html but of course the text input value will always empty.
function swap1( ) {
$("body").html('<button onclick="swap2();">SWAP2</button><input type="text" placeholder="swap2"/>');
}
function swap2( ) {
$("body").html('<button onclick="swap1();">SWAP1</button><input type="text" placeholder="swap1"/>');
}
With not knowing what form inputs there are, how would one swap in and out these forms in the BODY and keep track of the form states?
Demo of two text inputs which should keep state when they come back into the BODY:
https://jsfiddle.net/g7hksfne/3/
Edit: missunderstood use case. This covers saving the state while manipulating the DOM, instead of switching between different states.
Instead of replacing the <body>'s content by serializing and parsing HTML, learn how to use the DOM. Only replace the parts of the DOM you actually change, so the rest of it can keep its state (which is stored in the DOM).
In your case: you might want to use something like this:
function swap1( ) {
document.querySelector("button").onclick = swap2;
document.querySelector("button").textContent = "SWAP2";
document.querySelector("input").placeholder = "swap2";
}
function swap2( ) {
document.querySelector("button").onclick = swap1;
document.querySelector("button").textContent = "SWAP1";
document.querySelector("input").placeholder = "swap1";
}
<button onclick="swap1();">SWAP1</button><input type="text" placeholder="swap1"/>
(This is not optimized and should only serve as an example.)
Put the content you want to save in a node below <body>, like a simple ´` if you don't already have a container. When you want to save and replace the container, use something like:
var saved_container = document.body.removeChild(document.querySelector("#app_container");
// or document.getElementById/getElementsByClassName, depends on container
The element is now detached and you can add your secondary to document.body. When you want to get back, save the secondary content (without overwriting the first container of course), then reattach the primary content it with:
document.body.appendChild(savedContainer);

Issue with tree traversal, finding div ID to be used variably - jquery

so I've been trying to figure this out but I'm coming up short. Have really tried searching the best I could to come up with the answer, including jQuery API documentation and other SO posts. I feel like I'm almost there but I'm either misunderstanding something or I'm approaching this goal incorrectly.
For multiple different sections, I have 2 clickable icons in separate div's, 1 (lets say iconA) shown on load and 1 hidden (iconB) on load. When (iconA) is clicked, it hides the [sectionA] where (iconA) is located then shows the [sectionB] where (iconB) is located. I then want (iconB) to hide [sectionB] and show [sectionA].
Clearly I can't use toggle because one of the sections is always hidden at any given point. And since I'm trying to write a script that I can use for multiple sections and multiple icons, with different names, I can't just set 1-1 class names for ALL icons and sections.
I've created a jsfiddle to illustrate. Below I'll write a quick example.
HTML:
<div class="sectionAparent>
<div class="sectionA" id="example>
<i class="fa fa-code contbtn">iconA (shown on load)</i>
</div>
</div
<div class="sectionB" id="exampleSHOW">
<i class="fa fa-minus minushide">iconB (hidden on load)</i>
</div>
jQuery:
$('.contbtn').click(function(){
var contid = $(this).attr('id');
$('#'+contid+'show').slideToggle(1000);
$(this).hide(1000);
});
-this first one is to hide sectionA and show sectionB, which works fine.
$('.minushide').click(function(){
var cbtn = $(this).closest('.sectionB').siblings('.sectionAparent').find('div[id]');
var cid = $(cbtn).attr('id')
$('#'+cid+'show').slideUp(1000);
$(cid).slideDown(1000);
});
-So my thoughts were to jump up to the closest ancestor that is a sibling to the section containing the ID that I need. Then find the div with that ID, retrieve that ID, and use it show the section containing the ID and hiding the section with the ID+more. The goal is for this to be variable for multiple different sections with similar naming conventions without having to hard-code the section names in a list inside my script.
Hope this makes sense and I apologize for the wall of text, just wanted to make sure I conveyed what I'm trying to do and where I'm at. If my logic is incorrect or there is an easier way to do this, then I'm all ears! Thanks.
https://jsfiddle.net/dankbawls/wnjxwyfy/
You forgot to append the '#' character to sid in the second last line of the js
Updated fiddle
$('#'+sid).slideDown(2000);
Since you are using class (sectionhide) to toggle visibility, you can look into .toggleClass method.
It has an overriden constructor to accept 2 arguments, className and state (a boolean value)
Based on this state, it will add/remove class. True means add and false means remove
$('.minushide, .contbtn').on("click", function() {
var container = $(this).closest('.container');
var nextContainer = container.next('.container').length > 0 ? container.next('.container') : container.prev('.container');
container.toggleClass('sectionhide', true)
nextContainer.toggleClass('sectionhide', false)
})
Sample Fiddle
Note: I have added a common class container to both divs to have a common pattern
For a carousel kind of behaviour, you can use index to find index of element to be shown and hide all.
Sample Fiddle

How to add dynamic parameters/variables to templates rendered with ng-bind-html or custom directive (inside ng-repeat)

EDIT: Here is the solution sample based on the first answer. You're still welcome to offer further suggestions and fill some gaps in my knowledge (see comments).
plnkr.co/edit/mqGCaBHptlbafR0Ue17j?p=preview
ORIGINAL POST
Hello all Angular heads,
I’m trying to build a tool for building simple web pages from a set of predefined elements. The end user designs the layout by choosing which elements appear in which order (there would be a selection of maybe 20-30 different elements). An example layout:
Heading
Paragraph
Paragraph
Subheading
Barchart
Paragraph
…and so forth
Under the hood, there would be an array of Javascript objects:
var page_structure = [
{type: ”heading”, content: ”The final exam - details” },
{type: ”paragraph”, content: ”Bla bla bla bla bla…” },
{type: ”paragraph”, content: ”Bla bla bla bla bla…” }
…
{type: ”bar chart”, y: ”Grades”, colour: ”blue” }
…
];
The end user inputs parameters like content, variable, colour, etc, for each individual element.
THE PROBLEM
I can’t figure how to draw these elements on the page so that the dynamic parameters for each element are properly included.
Each element type (heading, paragraph, bar chart, other possible elements) has it’s own HTML template, which has to be able to dynamically display user-defined parameters. I’m thinking I need something like this:
var templates = {
heading: ”<h1>USER_CHOSEN_PARAMETER_HERE</h1>”,
paragraph: ”<p>USER_CHOSEN_PARAMETER_HERE</p>”
…
};
I’m using Angular’s ng-repeat directive to draw each element. I have tried using either ng-html-bind…
<div ng-repeat="x in page_structure track by $index">
<div ng-bind-html="templates[x.type]"></div>
</div>
…or a custom directive, which I call mycomponent:
<div ng-repeat="x in page_structure track by $index">
<div mycomponent component='x'></div>
</div>
Both methods work just dandy when there are no user defined parameters in templates. I can’t, however, wire up the parameters. With ng-bind-html, I have tried using an expression markup like this:
var templates = {
heading: ”<h1>{{x.content}}</h1>”,
paragraph: ”<p>{{x.content}}</p>”,
…
};
(I actually define templates in app controller constructor, so it’s $scope.templates = { bla bla } to be precise.)
This is just showing curlies and ”x.content” in the actual web page. How do I refer to a dynamically variable parameter inside ng-html-bind template, or is it even possible?
I also tried the custom directive route, defining the directive as
.directive('mycomponent', function() {
return {
scope: { component: "=" },
template: templates[component.type]
}; )
This was even more messed up, since I actually couldn’t figure out how I should even try to refer to a dynamic parameter here inside the template. So I apologise my inability to offer a meaningful example of what I tried to do.
Any help or working examples of the methods I should use here are greatly appreciated. I’m happy to provide more details if needed (this is my first post in SO, so I’m still trying to get the jist of how to flesh out the questions).
I suggest using ngInclude, in which you can have a funciton that check for the proper template to load based on the passed page structure.
<div ng-repeat="structure in page_structure">
<div ng-include="getMyTemplate(structure)"></div>
</div>
$scope.getMyTemplate = function(structure) {
switch (structure.type) {
case 'heading':
return '/Views/Heading.html' // or id of a pre-loaded template
case 'paragraph':
return '/Views/Paragraph.html' // or id of a pre-loaded template
}
}

Reactjs append an element instead of replacing

I'm trying to iterate through a list/array/object of things: (I used coffeescript to keep it clear, jsfiddle of full JS here. but it's just a forEach)
pages = for page, each of #props.ids
$('#start').append("<div id='"+page+"' ></div>")
React.renderComponent page(title: each.title, text: each.text), $("#"+page)[0]
and append each of them, instead of replacing, leaving only the last item in the list.
Where the #start element is the starting container, and I want to populate it with multiple elements, but I need to give each their own container, otherwise they will all overwrite eachother, the default reactjs behaviour.
I'm wondering if there's a way to tell react to append instead of replacing the div.
I'd like to avoid using jquery if possible, and do it purely react-ly.
I though about giving the React.renderComponent page the initial list, and then iterate in the previously called template, however, then i'm facing a different problem, I have to return a reactjs element object, consisting of the whole list, which I really don't prefer.
I need for the initial call to create individual, independent react templates, appending eachother in a list, prefferably without any extra containers, or using jquery.
I think you're getting the concept wrong. React's renderComponent indeed renders a single component, somewhere. Doing this multiple times only re-renders the same component at that place (aka idempotent). There's no real "append" statement, at least not in the way you asked for.
Here's an example of what you're trying to achieve. Forgot about renderComponent in this. It's just to put the component somewhere.
/** #jsx React.DOM */
var pages = [{title: 'a', text: 'hello'}, {title: 'b', text: 'world'}];
var App = React.createClass({
render: function() {
return (
<div>
{
this.props.pages.map(function(page) {
return <div>Title: {page.title}. Text: {page.text}</div>;
})
}
</div>
);
}
});
React.renderComponent(<App pages={pages} />, whateverDOMNodeYouWantItToBeOn);
See what I did there? If I want multiple divs, I just create as many as I want to see. They represent the final look of your app, so making a same div be "appended" multiple times doesn't really make sense here.
Create a div with a class extradiv:
<div class="extradiv">
</div>
In CSS, Set It's display to none:
.extradiv {
display: none;
}
.extradiv * {
display: none;
}
In JS implement this function:
function GoodRender(thing, place) {
let extradiv = document.getElementsByClassName('extradiv')[0];
ReactDOM.render(thing, extradiv);
extradiv = document.getElementsByClassName('extradiv')[0];
place.innerHTML += extradiv.innerHTML;
}
Than you can use this in place of ReactDOM.render:
GoodRender(<Component>My Text</Component>, YourDOMObject)

Categories

Resources