Get property of DOM element the Angular 2 way - javascript

I need to get the width of a DOM element in pixles.
jQuery way...
var myWidth = $('.labels').width();
It looks like I need to get a hold of the ElementRef from within a #Component or Service and access the width property.
It also says that aside from security reasons, it can couple the app and the rendering layers therefore preventing future deployment to a web worker.
So what is the best way to access that div width? I am working with an image that fills its div horizontally. I am overlaying some elements and I make the calculation myHeight = aspectRatio * myWidth;
All of the related questions I see mention how to do it back while Angular2 was still in the release candidate stage. So many API changes in the stable release (a month and 4 days as of today) that I feel like some sort of #deprecated tag would be helpful.

Angular itself doesn't provide anything to read from the DOM.
If you want to read from the DOM you need to use ElementRef.
Using ElementRef is far less of a security concern than for example using jQuery.
It's correct that you prevent this application to work properly with server-side rendering or webworkers if you do.

Related

How to programmatically insert an Ember component into a div?

I am trying to figure out a way to use Ember components as a view template for tooltips. Let me explain this:
I am supposed to create a library to show tooltips in Ember. The content of this tooltip is unknown. It might be very complex or it might be a simple text. The developer is the one who will decide it but the library must offer a way to do it easily. Also, I want to offer this solution in the format of an Ember modifier so that the developer would code it something like:
<div {{tooltip foo bar}}>
Hello World
</div>
As the modifier offers a reference to its element it is easy to use the good old JS to create elements and append them to this element. For a simple text it works like a charm and I was able to do it already as shown in the example below, but for complex component it's better to create a component and show it inside the tooltip's container.
// tooltip.js
import { modifier } from 'ember-modifier';
import { isPresent } from '#ember/utils'
export default modifier(function tooltip(element) {
const content = document.createElement('span')
content.append('Hi, I am the tooltip\'s text')
element.append(content)
});
The problem starts when you want to build a complex view, specially if it's supposed to contain some logic associated.
What I thought is that I could programmatically insert Ember components into the element that is passed as the argument of the modifier function. I can't use the dynamic component helper ({{component}}) as it infers that I have to mess with .hbs files more than what I am doing already and I can't approach it using the tooltip as a component; I need it to be a modifier.
I looked into this solution here but it doesn't seem to work in Ember 3.8.
Can anybody give me a clue on how do make it happen?
I am using Ember 3.8 and Ember Modifier#1.0.5
You could use the same technique that either of these use:
https://github.com/NullVoxPopuli/ember-popperjs
https://github.com/CrowdStrike/ember-velcro
They allow for "any content tooltips" by using an external library (popper or floating-ui, depending -- these are important though, because positioning is hard).
The gist is the following:
modifier on the "reference" / "hook" element (what you hover over)
modifier on the "target" / "popover" / "loop" element
some code that communicates between the two modifiers to wait until both are present before rendering the tooltip in the correct location / position.
The key part missing from your original code is that you need two modifiers -- tooltips with complex content are not possible with a single modifier (unless you manually manage element references).
For ember 3.8, I don't know how much you'll be able to do.
Ember 3.28 is the oldest LTS supported now and is passed its last bugfixes date, and it will step receiving security patches in January -- see: https://emberjs.com/releases/lts/
you may be able to use 2 global modifiers and a service to communicate between them -- but I don't know how that would work when you attempt to have multiple tooltips / popovers on the screen at the same time.
The minimum ember version you need to use the two addons linked above is 3.27.
Personally, it's well worth the upgrade, as staying up to date is generally easier than leap frogging years at a time (because you have the community doing upgrades with you) -- and shiny stuff is fun :)

Creating a content editable word processor using Vue

I'm interested in developing a word processor type application with a structure like this:
Document -> pages -> paragraphs
I essentially want to get to a point where I'm able to do something like this:
var page_4_content = document.pages[4].paragraphs;
This document would need to be contenteditable. I've already built a rudimentary version using jQuery but it is slow as hell in processing all the paragraphs on a 100 page document. I've been looking at alternatives and was wondering if Vue will give me better performance and an easier way to manage the document content instead of having to use selectors all the time?
Specifically, pages have a fixed height so if adjusting an element causes the page height to change, the whole document needs to be repaginated and this locks up the browser.
I'm wondering if Vue's use of a virtual DOM will alleviate that problem?
Many thanks!

Restrict access to 'style' property in JavaScript

I'm starting to develop a small JavaScript library and I want to make styling of HTML elements possible only through my API (because for some reason I need to have full control over styling).
So I want to make style property inaccessible (my API will access it through my style alias - not an ideal solution, but for other libraries like jQuery it will do the trick).
If I write this (inspired by this topic):
var box = document.getElementById('someElementId');
Object.defineProperty(box, 'style', {
get: function() {
throw 'you cant access style property';
}
});
box.style.color = 'red';
it works for box element only.
Is it possible to do this for all (existing and future) elements in Webkit, Firefox, and IE9+?
I've also tried this:
Object.defineProperty(HTMLElement, 'style', {...
but no luck.
Any help would be greatly appreciated!
Edit
As #Teemu suggested I can write HTMLElement.prototype instead of HTMLElement, and it works fine in FF and IE, but not in Chrome. And it looks like a Chrome bug. Sadly...
Edit2 - why do I need it
The main goal of a library I want to develop is to allow writing styles like:
element.setWidth('parent.width / 2 - 10');
In this case element's width should react on each changing of the parent's width.
But since onresize event is available only for window object (this article seems to be obsolete),
the only way I can "listen" modifying .style.width property is to perform my own API for styling.
And I want to restrict (or at least show warning) direct style modifying because it will break the elements' behavior.
From the comments you can tell that restricting access to the style property is probably not such a good route. But I understand from your question that your reason from trying to go this route is that the resize event only fires for the window object.
If you would be able to circumvent the whole restricting issue with a resize event on just any element, than may I suggest you look into Ben Alman's jQuery resize event plugin. I'm not sure whether you want to develop with jQuery, but even if you don't it may be worth it to read that plugin's code. Basically, what it does is make a hashtable of listeners mapped to the element(s) they are listening on and then in a polling loop (with setTimeout or setInterval) check the size of the elements in that map. If it has changed during the interval (250ms by default) it triggers the listeners itself. It works reasonably well. That specific plugin hooks into jQuery's event system, but you could just make your own addResizeEvent function or something to that effect.
Edit: Upon re-reading your question it dawns on me that it looks like you are trying to develop some mechanism to deal with the downsides of the CSS box model, e.g. that when you give an element 5px padding and a width of 50% it will end up being 10 pixels wider than half the parent container. Consider box-sizing: border-box if that is the case.

Javascript widget implementation

I have a question about Javascript widgets. The widget I am working on simply embeds content on a page instead of using iframes. So far it looks good. But there are cases where some users layouts are messing up the widget. For example, the widget might require a width of 300px to appear. But the parent div is set to 250px and hence the right part of the widget is cut off.
I was wondering what sort of precautions should be taken to prevent this? I was talking to the product manager who mentioned he wanted me to check the parent div elements and get the size and then show an alternate message if their size is not accurate. But again, since this is Javascript and the widget is supported in many diff browsers(including IE6), I am wondering how fail-safe this method would be? What if I need to iterate the DOM all the way up before getting a valid size? I am also worried about performance here. This extra checks would slow down the delivery of my widget content to "good users" since I am adding a layer of complexity to all users. I don't want to penalize good users just because of the few errant ones.
I am not using any sort of JS library here, so any solution should not suggest the use of one. Also, the reason for not using a library was simply not to add extra weight to the page load to deliver a widget. I understand that "jquery" for example is small, but in my case, even 24k compressed seems like an overkill for a widget delivery that contains no core code for the widget.
Has anyone dealt with such issues before? What are your solutions to these?
There are reliable ways of determining the size of an element using JavaScript. You're quite right that you may need to iterate up the tree in some cases, but the answer you get will ultimately be quite valid.
Although you don't want to directly include any library code in this project, you may consider looking at how the major libraries implement their "what's the width of this element" functions to drive your own implementation.
Beware of quirks mode too.
I'd check to see of the page has Jquery, if not load it into the page using no-conflict mode. Then use jQuery to examine the page.
See: How to embed Javascript widget that depends on jQuery into an unknown environment

Question - Setting dynamic HTML using Javascript to iFrames on Windows Mobile 6.1 - IE Mobile6

(excuse me if this is not the right forum to post - i couldn't find anything related to non-native programming and related to this topic)
I Am trying to set a dynamic HTML into an iFrame on the webpage. I have tried a couple of things but none of them seem to work. I m able to read the innerHTML but can't seem to update it.
// Able to read using
document.getElementById('iFrameIdentifier').innerHTML;
// On Desktop IE, this code works
document.getElementById('iFrameId').contentWindow.document.open();
document.getElementById('iFrameId').contentWindow.document.write(dynamicHTML);
document.getElementById('iFrameId').contentWindow.document.close();
Ideally the same function should work as how it works for div's but it says 'Object doesn't support this method or property".
I have also tried document.getElementById('iFrameId').document.body.innerHTML.
This apparently replaces the whole HTML of the page and not just the innerHTML.
I have tried out a couple of things and they didn't work
document.getElementById('iFrameId').body.innerHTML
document.frames[0].document.body.innerHTML
My purpose is to have a container element which can contain dynamic HTML that's set to it.
I've been using it well till now when I observed that the setting innerHTML on a div is taking increasing amount of time because of the onClicks or other JS methods that are attached to the anchors and images in the dynamic HTML. Appears the JS methods or the HTML is some how not getting cleaned up properly (memory leak?)
Also being discussed - http://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/Q_26185526.html#a32779090
I have tried a couple of things but none of them seem to work.
Welcome to IEMobile! Nothing you know about DOM scripting applies here.
Unfortunately, cross-iframe scripting does not appear to be possible in IEMobile6-7.
frameelement.contentDocument (the standard DOM method) isn't available
frameelement.contentWindow.document (the IE6-7 workaround version) isn't available
the old-school Netscape window.frames array only works for frames, not iframes
having the child document pass up its document object to the window.parent only works for frames, not iframes. In an iframe, window.parent===window.
So the only ways forward I can see are:
use frames instead of iframes. Nasty. Or,
use document.cookie to communicate between parent and child: the child document is just a script, that checks for a particular cookie in document.cookie on a poller, and when it's found that's a message from the parent, and it can write some HTML or whatever. Slow and nasty. Or,
using the server-side to inject content into the frames, passing it in as an argument to a script. Slow, nasty, and potentially insecure. Or,
avoid frames completely (best, if you can). Or,
drop support from IEMobile6-7 (best for preserving your sanity, if you can get away with it!)
Appears the JS methods or the HTML is some how not getting cleaned up properly (memory leak?)
Yes, probably. IEMobile6-7(*) is close to unusable at dynamic HTML. It gives you a lovely flavour of what scripting used to be like for us poor gits back in the Netscape 4 days.
Try to avoid creating and destroying lots of nodes and event handlers. Keep the page as static as possible, re-using element nodes where possible and setting text node data properties in preference to tearing everything down and making anew with createElement or innerHTML. Use an event stub (onclick="return this._onclick()") in the HTML together with writing to _onclick if you need to set event handlers from JavaScript, in preference to recreating the HTML with a new event handler (or just trying to set the property, which of course doesn't work in IEMobile). Avoid long-running single pages when you can.
It'll still crash, but hopefully it'll take longer.
*: that is, the versions of IE present on WinMo before version 6.1.4, where it became the infinitely better IEMobile8, marketed as “Internet Explorer Mobile 6” (thank you Microsoft).
Okay, I kinda resolved the issues that i was facing earlier and the bigger issue which was setting HTML to an iFrame on IEMobile. But i still have one more PIA which is related to double scollbars - which i am currently looking into. There seems to be more poor souls facing similar problem - if i fix that too. I will post an update here.
How did i finally write to iFrame on IEMobile?
Have 2 divs one to wrap the iFrame and the other to write inside an iFrame.
document.getElementById('OuterDiv').innerHTML = '';
document.getElementById('OuterDiv').innerHTML = '<iframe id="iFrameId" src="somefile.html"></iframe>';
This creates an iFrame each time and in the somefile.html on load there is a InnerDiv.innerHTML which doesn't seem to leak the memory.
In the somefile.html there will be an onLoad method which will fetch the HTML (explained below on how i managed to get it) and do a
document.getElementById('InnerDiv').innerHTML = dynamicHTML;
How did I manage to pass the HTML between parent and child iFrame
As well explained by #bobince earlier, one has to rely on 3rd party service like a cookie or a server to pass around the data between parent and the child iFrame.
I infact used an ActiveXControl to set and get data from the parent and child iFrame's javascript respectively. I won't recommend doing this if you have to introduce an ActiveX Control just for this. I accidentally already have one which I use to get the Dynamic HTML in the first place.
If you need any help you can DM me - Twitter #Swaroop
Thanks #bobince for your help. I am marking this one as an answer because it says what i did to fix the issue.

Categories