Can't change element's height - javascript

I'm trying to resize element by dragging (like so). I wrote a simple directive (will handle ghostbar later):
#Directive({ selector: '[drag-resize]' })
export class DragResizeDirective {
private dragging: boolean;
constructor(el: ElementRef, renderer: Renderer2) {
renderer.listen('window', 'mouseup', (e) => {
if (this.dragging) {
el.nativeElement.style.backgroundColor = 'red'; // Works fine.
el.nativeElement.style.height = `${e.pageY + 2}px`; // Not so much.
this.dragging = false;
}
});
}
#HostListener('mousedown') onMouseDown() {
this.dragging = true;
}
}
The problem is I can't change height of the element. Other styles work fine. I'm using Angular 4.0.3.
Computed attributes:
display: block;
height: 244.781px;
left: 0px;
overflow-x: hidden;
overflow-y: scroll;
position: absolute;
top: 655.422px;
width: 1793px;
*renderer.setStyle() doesn't work either.
** Element I'm trying to resize is a grid tile (md-grid-tile from Angular Material).
*** Directive works on other elements.

Edit 2:
I've dug into the md-grid-list implementation. The row height is recalculated everytime that ngAfterContentChecked is triggered (code). This happens after every mouse event and is probably the reason why setting the height has no effect.
From the md-grid-list documentation I can see that you can also pass a rowHeight (e.g. 200px) input parameter to the `md-grid-list. This seems to be cleanest way to set the row height, but will scale all rows to the same size.
If this is not the effect you want to achieve, you can try setting the height in the ngAfterViewChecked lifecycle hook.
Edit:
In case your code is trying to resize a display: inline element, you first have to apply a e.g. display: inline-block to it. Otherwise it will ignore the height value.
The style.height attribute expects numeric values to have a unit (e.g. %, px, rem, em, vh).
This should work:
el.nativeElement.style.height = `${e.pageX + 2}px`;

Related

Is it possible to apply the class changes to an element of selection.classed() in d3.js, or to set a CSS property value relative to its currentValue

I am using d3.js to add and remove classes to a selection of elements on mouseOver() and mouseOut() events. I'd like to make the class "isHovered" and make the values of the attributes I'm changing to be relative to the element's current value. Something like this:
function handleMouseOver(d, i) {
d3.selectAll('.classToSelect')
.classed('isHovered', 'true');
};
function handleMouseOut(d, i) {
d3.selectAll('.classToSelect')
.classed('isHovered', 'false');
};
and make the isHovered class change the elements size/color:
.isHovered {
height:height*1.5;
width:width*1.5;
background-color:yellow;
}
This adds the class, but doesn't actually make any changes to the elements attributes, except its classList. I'm trying to assign and unassigned the "isHovered" class, rather than having to store the pre-hovered size/color, and manually update them, and then manually revert back to them afterwards, which I don't think is possible since these elements are sized dynamically by d3.js scaling data:
So, can I make these newly added class changes actually take effect, and can the effect be relative to an element's properties' current values?
Alternatively:
Is it possible to access the element's width:svgAnimatedWidth and Height:svgAnimatedHeight properties & values directly, so that I can change them and revert them back manually? How?
There are various ways of altering the height/width on hover.
This snippet uses CSS variables to set the initial height and width in a class and then uses them to calculate new values in the isHovered class.
const div = document.querySelector('div');
div.addEventListener('mouseover', function() {
div.classList.add('isHovered');
});
div.addEventListener('mouseout', function() {
div.classList.remove('isHovered');
});
div {
--h: 100;
--w: 200;
height: calc(var(--h) * 1px);
width: calc(var(--w) * 1px);
background-color: blue;
}
.isHovered {
--hhovered: calc(var(--h) * 1.5);
--whovered: calc(var(--w) * 1.5);
height: calc(var(--hhovered) * 1px);
width: calc(var(--whovered) * 1px);
background-color: yellow;
}
<div></div>
It is also possible to alter CSS variables using JS style.setProperty and to read them using style.getPropertyValue.
As a complete alternative if the aim is just to increase the height and width of an element on hover then the CSS transform scale could be used.
div {
height: 100px;
width: 200px;
background-color: blue;
}
div:hover {
transform: scale(1.5);
background-color: yellow;
}
<div></div>
This has the advantage (or disadvantage, depending on what effect is actually required) of not affecting surrounding elements' positioning.

mxgraph: I would like to add a button to disable/enable the graph and toolbar

I tried to disable the graph by not allowing the cells on graph with follow code.
graph.setCellsSelectable(false);
but it is not working, still can select cell, (only disabled resizing)
And for the toolbar to be disabled, I tried to remove or replace ondrag event, is that correct? In theory I think mxgraph has their own event handler for dragging of toolbar item.
mx_toolbar.appendChild(
mxUtils.button("Disable/Enable", function() {
document.querySelectorAll('.toolbar > button').addEventListener(function (e) {
e.preventDefault()
return false;
});
}
)
Hope your help. I dont mind as long as it is working solution.
Thanks
Instead of removing or modifying the event handler, you can simply overlay the area you want to disable along with css.
var toolbarContainer = document.querySelector(".toolbar");
var overlay = document.querySelector(".toolbar-overlay")
if (!overlay) {
overlay = document.createElement('div')
overlay.className = 'toolbar-overlay'
toolbarContainer.appendChild(overlay)
} else {
overlay.parentNode.removeChild(overlay)
}
Here is css for the overlay div
.toolbar-overlay {
position: absolute;
top: 0;
height: 100%;
width: 100%;
opacity: 0.4;
background: #e1e1e1;
}
Note: You should make sure the parent div of the overlay div must positioned as relative to make this css working!

Transitions not working when setting .cssText on an element's style?

I have the following CSS snippet:
.Test-Content {
transition: height 2s;
}
and the following HTML code:
<div id="mydiv" class="Test-Content">foo</div>
Using pure JavaScript, I am trying to change the height of the div like that:
myId = document.getElementById("mydiv");
myId.style.cssText = "height: 0;";
/* ... Lots of code and situations where the browser re-renders the page ... */
myId.style.cssText = "height: 100px";
This indeed changes the div's height from whatever it was to 0 and then to 100px, but without any animation, i.e. immediately. I don't understand why this happens. After all, the div has .Test-Content in its class list, so any change of its height should trigger the transition.
Could anybody please explain why this is not the case?
When I change this to the following (very weird and worrying) code, it works as expected:
CSS:
.Test-Content-A {
transition: height 2s;
height: 0;
}
.Test-Content-B {
transition: height 2s;
height: 10px; /* or whatever number you prefer */
}
HTML:
<div id="mydiv" class="Test-Content-A Test-Content-B">foo</div>
JavaScript: (Same as above)
It seems that I can trigger a transition by setting an element's style.cssText directly only if this element also has two classes with different height properties in its class list.
I have that problem in Firefox and Chrome (didn't test others so far), both at current patch level at the time of writing this.
There are a couple things you can be running into as illustrated by the following snippet. The first time you click "Expand" or "Collapse", it won't animate, but then clicking "Expand" or "Collapse" after that will trigger an animation.
document.getElementById("expand").addEventListener('click', () => {
myId = document.getElementById("mydiv");
myId.style.cssText = "height: 100px";
});
document.getElementById("collapse").addEventListener('click', () => {
myId = document.getElementById("mydiv");
myId.style.cssText = "height: 0;";
});
document.getElementById("unset").addEventListener('click', () => {
myId = document.getElementById("mydiv");
myId.style.cssText = "";
});
document.getElementById("setandexpand").addEventListener('click', () => {
myId = document.getElementById("mydiv");
myId.style.cssText = "height: 0;";
setTimeout(() => { myId.style.cssText = "height: 100px"; });
});
.Test-Content {
transition: height 2s;
}
<div id="mydiv" class="Test-Content">foo</div>
<button id="expand">Expand</button>
<button id="collapse">Collapse</button>
<button id="unset">Unset</button>
<button id="setandexpand">Set and expand</button>
Issues you may be experiencing:
1. CSS can only transition from a value to a value.
Going from cssText = "" (the initial value) to cssText = "height: 100px" doesn't animate. You can reproduce this by clicking "Unset" then clicking "Expand" or "Collapse".
2. If CSS is set multiple times in a block of code, the browser will only process the last one.
The browser doesn't render changes immediately when they're set but instead switches between executing all executable JavaScript and updating the page based on what everything is set to. You can get around this by breaking it into two discrete steps. The best will probably be setting style="height: 0" in the HTML or adding a class with zero height.
Otherwise, you can do something like:
myId.style.cssText = "height: 0";
setTimeout(() => { myId.style.cssText = "height: 100px"; });
This code sets the height to zero, lets the browser update the style, then executes the new code setting the height to 100px, which the browser can animate. Of course, you only need to call cssText = "height: 0" because as soon as it's been rendered the browser will be able to animate.
You can see this in the snippet by clicking "Unset" followed by "Set and expand". The element will immediately decrease to zero and then expand to 100px. Clicking multiple times shouldn't appear to do anything because each time the browser will start animating down to zero then start animating back up to 100px within milliseconds.
One of the easiest ways to trigger CSS animations with JS is changing the class.
CSS:
.Test-Content {
height: 0;
transition: height 2s;
}
.Test-Content.taller {
height: 10px;
}
And then, with Javascript:
1) For adding the class (animating forwards)
document.getElementById("mydiv").classList.add('taller');
2) For removing the class (animating backwards)
document.getElementById("mydiv").classList.remove('taller');
This may not answer your question about why the transition isn't working with style.cssText. However, if you're wanting the div to change height right when the page loads, I recommend using an animation instead like the following:
.Test-Content {
transition: height 2s;
height: 100px;
animation: grow 2s;
}
#keyframes grow {
from {
height: 0
}
to {
height: 100px;
}
}
This eliminates the need to use JavaScript and better helps to keep JavaScript from doing what CSS can do.

Monaco editor dynamically resizable

I have been searching for a discussion about if it's possible to mimic the html tag textarea's resizing when using Monaco Editor's field all over the Internet but I couldn't find one answering my question.
I'm using the monaco-editor npm package in a React application. Do you have any idea if this is easy to implement?
Thank you in advance!
SOLUTION
With pure css I selected the target html element and just added these properties:
div {
resize: vertical;
overflow: auto;
}
TL;DR: add automaticLayout: true to your editor's configuration.
NL;PR:
Monaco has a built-in auto resize to parent container functionality:
createEditorWithAutoResize(){
this.editor = monaco.editor.create(
this.editorDiv.current, {
value: "var x = 0;",
language: 'javascript',
automaticLayout: true // <<== the important part
}
);
}
componentDidMount(){this.createEditorWithAutoResize();}
constructor(props){super(props); this.editorDiv = React.createRef();}
render(){return <div ref={this.editorDiv} className="editor" ></div>}
And the CSS for the editor (it avoids rendering the editor for the first time with like 10px height):
.editor{
height: 100%;
}
First tested: v0.10.1, Last tested: v0.32.1
Note:
< v0.20.0: The mechanism does not listen to its container size changes, it polls them.
#nrayburn-tech (Monaco Editor's contributor): Version 0.20 uses MutationObserver for all browsers. Version 0.21 and later uses ResizeObserver on supported browsers, otherwise, it uses polling as a fallback.
if you have a reference to the editor you can just call
editor.layout()
on some resize event.
For example, on window resize:
window.onresize = function (){
editor.layout();
};
For anyone coming here having this issue in a basic web app (html, css, javascript) I've found a solution for the resizing issue I'm experiencing.
I have the monaco editor in a resizable flex container. It will only grow the width, not shrink it, and vertical resizing doesn't seem to work out of the box.
If you use the monaco config "automaticLayout: true" and the following CSS it seems to resize as expected:
.monaco-editor { position: absolute !important; }
I tried the max-width 99% trick but it causes a laggy delayed effect when increasing the width near edge of page.
For posterity, the solution I arrived on was to set automaticLayout: false so that I could perform all the layout in a resize event listener.
const placeholder = document.getElementById('placeholder')
const editor = monaco.editor.create(placeholder, {
value: '// hello world',
language: 'javascript',
automaticLayout: false // or remove, it defaults to false
})
// we need the parent of the editor
const parent = placeholder.parentElement
window.addEventListener('resize', () => {
// make editor as small as possible
editor.layout({ width: 0, height: 0 })
// wait for next frame to ensure last layout finished
window.requestAnimationFrame(() => {
// get the parent dimensions and re-layout the editor
const rect = parent.getBoundingClientRect()
editor.layout({ width: rect.width, height: rect.height })
})
})
By first reducing the editor layout to 0 we can safely query the dimensions of the parent element without the child (editor) contributing to its size. We can then match the editor to the new parent dimensions. Since this takes place over a single frame, there should be no flickering or lag.
this is old question but get the problem to and solved it with react-resize-detector
based on ResizeObserver it feet perfectly to the need (check browser compatibility)
Exemple of component :
import React, { Component } from 'react';
import ReactResizeDetector from 'react-resize-detector';
import * as monaco from 'monaco-editor';
class Editor extends Component {
constructor(props) {
super(props)
this.state = {
width: 0,
height: 0,
}
this.editor_div = React.createRef()
this.handle_rezise = this.handle_rezise.bind(this);
}
componentDidMount() {
const editor_model = monaco.editor.createModel('', 'sql');
this.monaco_editor = monaco.editor.create(this.editor_div.current, this.props.editorOptions);
this.monaco_editor.setModel(editor_model);
}
componentWillUnmount() {
this.monaco_editor && this.monaco_editor.dispose();
}
handle_rezise(width, height) {
this.monaco_editor.layout({ height, width });
}
render() {
return(
<div
className="editor-container"
style={{ height: '100%' }}>
<ReactResizeDetector
handleWidth
handleHeight
onResize={ this.handle_rezise }
refreshMode="debounce"
refreshRate={100} />
<div
className="editor"
ref={ this.editor_div }
style={{ height: '100%' }} />
</div>
)
}
}
export default Editor;
Hope it's help
In my case I'm using that exact CSS but although automaticLayout: true works, I found out overkill (seems to pooling the DOM 100ms interval and I have several editors opened in the document. SO I ended up implementing it manually :
just in case , my needs are different: I want the user to resize it the container - in a standard way and cheap (both on code and performance) on libraries and performance. This is what I did:
css container : resize: vertical; overflow: auto
and this js :
function installResizeWatcher(el, fn, interval){
let offset = {width: el.offsetWidth, height: el.offsetHeight}
setInterval(()=>{
let newOffset = {width: el.offsetWidth, height: el.offsetHeight}
if(offset.height!=newOffset.height||offset.width!=newOffset.width){
offset = newOffset
fn()
}
}, interval)
}
const typeScriptCodeContainer = document.getElementById('typeScriptCodeContainer')
typeScriptCodeEditor = monaco.editor.create(typeScriptCodeContainer, Object.assign(editorOptions, {value: example.codeValue}))
installResizeWatcher(typeScriptCodeContainer, typeScriptCodeEditor.layout.bind(typeScriptCodeEditor), 2000)
yes, 2 seconds interval and make sure it registers only once. I see there is / was a resize interval on 100ms for the automatic relayout in monaco - IMHO that's too much.
See it in action: https://typescript-api-playground.glitch.me/?example=2

Change tinyMce editor's height dynamically

I am using tinymce editor in my page. What I want to do is to change the height of the editor dynamically. I have created a function:
function setComposeTextareaHeight()
{
$("#compose").height(200);
}
but that is not working.
My textarea is
<textarea id="compose" cols="80" name="composeMailContent" style="width: 100%; height: 100%">
I have tried all sorts of methods for changing the height but could not come to a resolution. Is there any thing that i am missing?
You can resize tinymce with the resizeTo theme method:
editorinstance.theme.resizeTo (width, height);
The width and height set the new size of the editing area - I have not found a way to deduce the extra size of the editor instance, so you might want to do something like this:
editorinstance.theme.resizeTo (new_width - 2, new_height - 32);
Try:
tinyMCE.init({
mode : "exact",
elements : "elm1",
....
To change size dynamically in your javascript code:
var resizeHeight = 350;
var resizeWidth = 450;
tinyMCE.DOM.setStyle(tinyMCE.DOM.get("elm1" + '_ifr'), 'height', resizeHeight + 'px');
tinyMCE.DOM.setStyle(tinyMCE.DOM.get("elm1" + '_ifr'), 'width', resizeWidth + 'px');
The following comes in from this other SO answer I posted:
None of the above were working for me in TinyMCE v4, so my solution was to calculate the height based on the toolbars/menu bar/status bar, and then set the height of the editor, taking those heights into consideration.
function resizeEditor(myHeight) {
window.console.log('resizeEditor');
myEditor = getEditor();
if (myEditor) {
try {
if (!myHeight) {
var targetHeight = window.innerHeight; // Change this to the height of your wrapper element
var mce_bars_height = 0;
$('.mce-toolbar, .mce-statusbar, .mce-menubar').each(function(){
mce_bars_height += $(this).height();
});
window.console.log('mce bars height total: '+mce_bars_height);
myHeight = targetHeight - mce_bars_height - 8; // the extra 8 is for margin added between the toolbars
}
window.console.log('resizeEditor: ', myHeight);
myEditor.theme.resizeTo('100%', myHeight); // sets the dimensions of the editable area
}
catch (err) {
}
}
}
In my case, I wanted the editor window to match the width and height of the actual window, since the editor would come up in a popup. To detect changes and resize, I set this to a callback:
window.onresize = function() {
resizeEditor();
}
It's a bit late but for Googler like me, check the autoresize plugin
tinymce.init({
plugins: "autoresize"
});
Options
autoresize_min_height : Min height value of the editor when it auto resizes.
autoresize_max_height : Max height value of the editor when it auto resizes.
I'm using tinymce 4.8.3.
I display the editor in a resizable modal dialog box.
I solved this using flexbox, shown here in SASS/SCSS:
// TinyMCE editor is inside a container something like this
.html-container {
height: 100%;
overflow: hidden;
}
.mce-tinymce {
// This prevents the bottom border being clipped
// May work with just 100%, I may have interference with other styles
height: calc(100% - 2px);
& > .mce-container-body {
height: 100%;
display: flex;
flex-direction: column;
& > .mce-edit-area {
flex: 1;
// This somehow prevents minimum height of iframe in Chrome
// If we resize too small the iframe stops shrinking.
height: 1px;
}
}
}
When the editor is initialized we have to tell it to put 100% height on the IFRAME. In my case I also have to subtract 2px else the right border is clipped off:
tinymce.init({
...
height: "100%",
width: "calc(100% - 2px)"
});
What ManseUK stated is almost correct.
The correct solution is:
$('#compose_ifr').height(200);
or in your case
$('#composeMailContent_ifr').height(200);
Update: maybe this is more what you are looking for:
// resizes editoriframe
resizeIframe: function(frameid) {
var frameid = frameid ? frameid : this.editor.id+'_ifr';
var currentfr=document.getElementById(frameid);
if (currentfr && !window.opera){
currentfr.style.display="block";
if (currentfr.contentDocument && currentfr.contentDocument.body.offsetHeight) { //ns6 syntax
currentfr.height = 200 + 26;
}
else if (currentfr.Document && currentfr.Document.body.scrollHeight) { //ie5+ syntax
currentfr.height = 200;
}
styles = currentfr.getAttribute('style').split(';');
for (var i=0; i<styles.length; i++) {
if ( styles[i].search('height:') ==1 ){
styles.splice(i,1);
break;
}
};
currentfr.setAttribute('style', styles.join(';'));
}
},
In case someone finds this and also wants to change the height of the source code editor plugin.
You need to edit the following file:
\tiny_mce\plugins\code\plugin.min.js
Look out for the attribute called minHeigh and adjust it to your needs. The height you define there is not the height of the entire box, but it is not the height of the textarea either. It is something inbetween.
You can set it according to your height
tinymce.init({
height: "500px"
});
I test this solution on version 5 of TinyMCE.
For change the height of TinyMCE after page loaded, all you need is: your element id
$(function(){
var selectedElement = tinymce.get('Element id without sharp(#)');
selectedElement.settings.height = 700;
selectedElement.settings.max_height = 400;
selectedElement.settings.min_height = 1000;
});
Also you can use autoresize plugin for get better experience:
tinymce.init({
plugins: 'wordcount autoresize',
})
$(window).load(function () {
$('#YourID_ifr').css('height', '550px');
});

Categories

Resources