I have a angularjs component, third party library creates the canvas inside the component's html file.
Following is the canvas created by third party library on page load.
<canvas style="width: 410px; height: 450px;"></canvas>
My current solution is, I am setting changing the CSS following way inside $postLink callback method.
var elem= angular.element(document.querySelector('#fooSelector canvas'));
elem.css('width', '420px');
But I read somewhere changing CSS and Manipulating DOM inside angularjs controller is not a good practice.
So How can I change inline CSS of element which is created dynamically by some third party library
changing CSS and Manipulating DOM inside angularjs controller is not a
good practice
This is just a common statement for beginners, this does not mean you can not or you should not - this means you should not if there is better and easier way.
When you create component that main purpose is wrap something like canvas, it is absolutely normal to change its position, width or whatever.
Though using query selector is not good - imagine you have 2 such components on page, then you will always select first canvas. So it is better to use $element.find:
$element.find('canvas').css('width', '420px');
Related
I'm trying to figure out the difference between using document.createDocumentFragment versus using an HTML <tamplate> element.
Is there a difference between them in behavior or performance?
Both <template> and document.createDocumentFragment are used for storing HTML-like data without rendering it, but the use cases are somewhat different.
The <template> tag's main purpose is to, as the name applies, store HTML for a later time, and or to be used repeatedly across the document. This tag is useful when using a template engine where the contents are usually never changed but the input may be different.
document.createDocumentFragment is used to create an entire DOM tree in JS without the browser rendering it, while still having the ability to use the DOM API with it. This useful when dynamically generating HTML by leveraging the DOM API, and to later inject the results in the actual document's DOM.
More: Template Tag and DocumentFragment
I'm a Polymer novice, but I guess what the answer will be...
Recently I came across with this issue: I got to loop through a collection of elements (using dom-repeat) and display its contents. But every element has a unique display and bindings, making it almost impossible to display each element dynamically. The ideal scenario would be to load a different component for each display type, but it looks like there is no easy way to achieve this.
Some options I have been thinking of were the following:
Using dom-if but it would add crap to my resulting HTML.
Is there a dom-switch? If it were something like that and didn't leave empty template tags (as it would do with dom-if) it would be nice.
It's possible to load a component dynamically? Using something like this: <[[item.type]] item-configuration=[[item.configuration]]></[[item.type]]>
Any other ideas? I would really appreciate any ideas or solutions or at least a workaround for my issue.
TL;DR; you can't
Polymer (and Web Components in general I guess) are best when used in a declarative way. Out-of-the-box your best solution is dynamically creating elements and adding to DOM or messy use of dom-if.
(potential) OPTION 1
I guess you could fairly easily implement a dom-switch element to work like
<template-switch switch="[[some.value]]">
<template-case case="10">
<element-one></element-one>
</template-case>
<template-case case="20">
<element-two></element-two>
</template>
<template-default>
<element-one></element-one>
</template-default>
</dom-switch>
I wrote this off the top of my head. There are multiple ways to implement such an element. A crucial decision is whether to use <template> internally or not. In this plunk I've implemented such element without templates but simply using content distribution.
OPTION 2
There is also Polymer.Templatizer.
Faced with a similar issue of choosing element to render dynamically I created this Plunk as a proof of concept.
As you see, you extend the <template> element with custom rules, which match against a model. You then bind the matched template's nodes with the model using Polymer.Templatizer.
Thanks to Templatizer, you don't have to pollute your actual element with conditionals and still get full binding functionality.
I'm working on a more feature-complete solution. If you're interested I could move it to a separate repository and publish.
Say I have an angularJS application, where I want to modify the dom. It makes sense that one should not do it via a service or a controller. Instead use a directive for DOM manipulations. But what should one do if the dom lies out of the scope of the angular app?
For Example:
Say I want to access the BODY tag and disable the scroll bars on it. I can't write a directive because ng-app directive is on a div which is deep inside the dom and thus the BODY tag is not accessible.
How does one tackle this problem? I read this blog, and it seems like it ok to do dom manipulations via a service. So what is really the best practice to access doms? Especially if its out of the scope of an angularjs app?
I'm not sure I understand without seeing your code. But in general, the ng-app should be at the highest tag that encompasses all the functionality you want to manipulate with angular. For most, that is the body tag itself.
I've had this happen to me three times now and I feel it's time I learned how to avoid this scenario.
Typically, I build the HTML. Once I'm content with the structure and visual design, I start using jQuery to wire up events and other things.
Thing is, sometimes the client wants a small change or even a medium change that requires me to change the HTML, and this causes my javascript code to break because it depends on HTML selectors that no longer exist.
How can I avoid digging myself into this hole every time I create a website? Any articles I should read?
Make your selectors less brittle.
Don't use a selector by index, next sibling, immediate child, or the like
Use classes so even if you have to change the tag name and the element's position in the HTML, the selector will still work
Don't use parent() or child() without specifying a selector. Make sure you look for a parent or child with a specific class
Sometimes, depending on the amount of rework, you'll have to update the script. Keep them as decoupled as possible, but there's always some coupling, it's the interface between script and HTML. It's like being able to change an implementation without having to change the interface. Sometimes you need new behavior that needs a new interface.
I think the best way to help you is for you to show a small sample of a change in the HTML that required a change to your jQuery code. We could then show you how to minimize changes to JS as you update the HTML
This is a follow-up question for In jQuery is it a bad idea to use name=X for all selectors?
I am using Backbone and decided that I wanted a way to differentiate between HTML elements that were bound and those that were not.
So I would write (in HAML):
.container
.title(name='title')
.separator
As you can see it's clear that the dynamic element is title.
The reason for this was so I could mess around with the style and rename classes without worrying about breaking the app. It also means in the template I can tell what the dynamic elements are without needing to go back and forth with the Backbone View.
My question now is, without using the [name] selector, does anyone have a code convention to keep track of which HTML elements are referenced from JS.
I have considering:
Using a common prefix on class names (e.g. class=bind-title)
Using some sort of custom HTML element (
Thanks!
FYI: I'm using CoffeeScript, Backbone and haml_coffee templates.
Updated jsperf to test all suggestions:
http://jsperf.com/class-or-name-attr-lookup/3
I would consider using a class to indicate that it is dynamic.
I'm not sure if you are aware of this but you can have multiple classes on one element. Like so:
.container
.dynamic.title(name='title')
.separator
This works in traditional HAML but I have not tried it with haml-coffee. If it doesn't work, you might have to specify the class like .title{:class => "dynamic"}(name='title').
I prefer this over a prefix on the class name because it's more semantically meaningful, which is how HTML should be used.
I am using data-view attribute on elements being set when rendering my Views.
This helps me to then show a tooltip in a browser window when I hover over View(s).