Workaround for mouseover in nested ng-repeat - css

I’ve been searching for some time and read about ng-repeat creating it’s own scope, but still did not find a solution.
I would like to have a mouseover event fired on each .event-window element. Using ng-mouseover="hoverIn()" doesn’t work. I expect because of trying to call a function that is not part of the scope, but only part of the parent (parent’s) scope, since the call works fine in elements that are not created with ng-repeat.
<div class="day-window" ng-repeat="day in weekObject['days']">
<div ng-repeat="event in day.events track by $index">
<div class="event-window" ng-style="{'height': (event.length)+'px',
'position': 'absolute',
'top':(1565/24)*(event.offsetTop-1) +'px',
'left': getLeftCoords(event.colliding)+'%',
'width': 100/event.colliding+'%',
'background': event.color,
'opacity': 0.8}" ng-mouseover="hoverIn()">
<p>{{event.title}}</p>
<p>[{{event.startTime |date:'H:mm'}} - {{event.endTime |date:'H:mm'}}]</p>
</div>
</div>
Controller
$scope.hoverIn = function() {
alert('hoverIn');
}
The hover in my css doesn’t work as well. Is it overridden by ng-style?
.event-window:hover {
opacity: 1.0 !important;
}
You can find a demo here, but I'm not able to replicate the problem. There must be some error in my code.

Related

How to use two svelte transitions on the same togglable element?

I have an input field that I want to hide/show and doing so with a fade and slide transition. I've have two examples that I came up with but both have their drawbacks and I'd like to know if there is a more elegant solution.
I just need one of the two questions to be answered as both of them would solve my problem.
Question 1: Is there a way to trigger multiple transitions for one transition-directive?
Question 2: How to add a class that will trigger an ordinary css-transition after an if-statement put the element in the DOM?
Example 1
Svelte does not allow two transitions on the same element. So one solution is to nest two elements as shown below. Is there instead a way to write a custom transition using both fade and slide transition:myMultiTransition?
{#if active === true}
<span transition:fade>
<span transition:slide>
<input type="text" />
</span>
</span>
{/if}
Example 2
In my other solution I just toggle an active class using a normal css transitions. The problem here is that the <input>-field never leaves the DOM. It's 0px height but it seems wrong to leave it there.
How to cuccessfully show the input field with an {#if active === true} and afterwards add a class that trigger the transition effect? Svelte seems to add the active-class that is supposed to trigger the transition before the element has entered the DOM.
I've tried to use await tick(), onMount, beforeUpdate in various combination with no luck.
When adding the class with a delay with setTimeout it works - but I don't like this solution because it could fail if not the timing is exact and I won't want a delay before the transition start.
<span class:{active}>
<input type="text" />
</span>
<style>
.active {
// Normal transition: opacity 1s etc ...
}
</style>
REPL
https://svelte.dev/repl/89cb7d26d9484d0193b4bc6bf59518ef?version=3.38.3
You can create your own transition function:
<script>
import { cubicOut } from 'svelte/easing';
let visibleDoubleElements = false;
function slidefade(node, params) {
const existingTransform = getComputedStyle(node).transform.replace('none', '');
return {
delay: params.delay || 0,
duration: params.duration || 400,
easing: params.easing || cubicOut,
css: (t, u) => `transform-origin: top left; transform: ${existingTransform} scaleY(${t}); opacity: ${t};`
};
}
</script>
<label>
<input type="checkbox" bind:checked={visibleDoubleElements}>
Svelte transition
</label>
{#if visibleDoubleElements === true}
<input transition:slidefade type="text" placeholder="Double elements" />
{/if}
REPL:
https://svelte.dev/repl/da8880947eff4f32b740a8742d9f817e?version=3.38.3
It might be the easiest to stick with the first solution you already provided: adding a wrapper for each transition.
If you want to reuse a specific combination of transitions it might be worth it to write your own one. At this point you can try to use the implementation from Svelte: Here is an example for Slide + Fade
function fadeSlide(node, options) {
const slideTrans = slide(node, options)
return {
duration: options.duration,
css: t => `
${slideTrans.css(t)}
opacity: ${t};
`
};
}
https://svelte.dev/repl/f5c42c6dc6774f29ad9350cd2dc2d299?version=3.38.3
Generic Solution (Theoretical)
In Svelte the transitions itself don't rely on CSS-transitions. A Svelte transition only provides the style for each transition step. Therefore a generic solution would be to create a merge-transition that takes 2..N transition functions and puts the styles from the individual transition together. Unfortunately this is not always trivial due to conflict situations in CSS.
E.g. combining two transitions... one where the opacity should be 0 and the other with a target opacity of 0.5. Question is: What should the output look like? If 0 is expected then there must be some logic which converts "opacity: 0; opacity: 0.5;" to "opacity: 0;". And there are surely more complex cases.

Vuejs apply loop in css to put hover

In VueJS, I have elements that have hover property in my object.
So, I want to put a foreach in style, but it is not possible.
I want to do that kind of thing :
<style>
#foreach (element in elements) {
if (element.has_backgroundhover) {
'#'+element.id:hover {
background : element.background_hover;
}
}
}
</style>
Notice that each element has a background color different (it is stored in his oibject property)
Thank you
The #mouseenter and #mouseleave event listeners would allow for css classes to be applied to each element.
For example, toggle a .hovered class that has the background color defined.
Something like this?
The HTML:
<div id="app">
<div
v-for="element of elements"
#mouseenter="element.hover=true"
#mouseleave="element.hover=false"
:style="{
background: element.hover? element.background_hover : element.background
}"
>{{element.name}}</div>
</div>
And the JS:
new Vue({
el: "#app",
data: {
elements:[
{
name:"element1",
background:"#f8f",
background_hover:"#a4a",
hover:false
},
{
name:"element2",
background:"#ff8",
background_hover:"#aa4",
hover:false
},
]
},
})
This is not using the CSS, rather using events as suggested by #DigitalDrifter. I think the point is that reactive css is not a good idea, and not supported in vue. Instead you need to have the HTML element properties dependent on your vue data object. A fiddle for this is: https://jsfiddle.net/edzaokum/

Restate(override) css-transition after it has already triggered

Is it possible to restate(override) css-transition after it has already triggered?
It seems down right impossible to override transition-delay after the css-transition has already taking effect.
(Especially considering the possible case when delay duration might have past already, delay value gets shortened and so on.)
However I failed to find concrete explanation.
I suppose css-transition has to be instructed at before or the exact same time when the change of target property (background-color in this case) is instructed?
(Sorry I had to edit numerous times to narrow down my question. If anyone wonder why I need such thing, I explained a mechanism I want below. It's already in simplified of my project.)
What I'm trying to do is
Before jQuery 'load' event, background-color: transparent is applied.
Then on jQuery 'load' event, apply background-color: red
(which is determined by css with class name loaded added by jQuery).
On the otherhand, transition-delay is determined separately by its class name which is provided by jQuery.
Clarification
Just to differentiate from other similar questions..
I only need transition-delay to be override conditionally.
Although interestingly, it would succeed when background-color is changed alongside.
Overriding happens conditionally, i.e: CSSOM remains constant but DOM's class name might change after its initial state. (To be specific to this case, class is added when the button is pressed.)
Override succeeds while DOM stays constant, but that's not what I want.
Here's fiddle to illustrate the situation
HTML
<div>
<!-- class name "loaded" will be given after load event. -->
<p class="delay delay-1s">
<!-- class name 'delay-1s' will be replaced with 'delay-5s' with button -->
This will be turning into red after loaded in..<br>
1.) 1 seconds without button or<br>
2.) 5 second with button
</p>
</div>
<button id="change-delay">Change delay to 5s</button>
CSS
/* Make P from transparent to red when loaded */
div p {
background-color: transparent;
}
div.loaded p {
background-color: red;
}
.delay.delay-1s {
transition-delay: 1s;
}
.delay.delay-5s {
transition-delay: 5s;
}
Javascript
$(window).on('load', function(){
$('div').addClass('loaded');
});
$('button#change-delay').click(function() {
$('.delay').removeClass('delay-1s').addClass('delay-5s');
});
I tested this on Chrome/Firefox updated to this day (Sep 2017), but both returned the same result.
edit1:
I'm pretty sure this has something to do with the time to provide class name.
If I add the class btn-pressed in HTML, i.e hardcode them on the document, override works as intended. Although, it wouldn't happen exclusively when the class is modified.
edit2:
Added clarification.
edit3:
Narrowed down question.
edit4:
adding timelapse of event happening on code:
Loads document.
P gets background-color: transparent and transition-delay: 1s;
Loading is done, adding class 'loaded' to DIV,
P gets background-color: red and fires css-transition
BUTTON gets clicked*, adding class 'btn-pressed' to DIV.
P gets transition-delay: 5s; assigned, overrides CSSOM; however, since css-transition from 2. is already in action, it doesn't take effect.
*Surely, if BUTTON has clicked before loading completed, it will take effect.
I was too lazy to read W3C documents but maybe that's what I should do in spare time..
Html code here
<div class="bg">
<p>test here</p>
</div>
<button class="btn">Activate</button>
Css code here
.bg {
min-height: 200px;
background-color: transparent;
}
Js code here
$(window).on('load', function(){
var delay = 5000;
If ( $('.bg').hasClass('pressed') ) {
delay = 2000; //set delay to 2 sec,
}
$('.btn').on('click', function() {
$('.bg').addClass('pressed');
});
$('.bg').animate({
'background-color': 'red'
}, delay);
});
I assume that you have jquery. If any issue plz let me know by putting a comment below.
I hope this is what you need.
Note - Make few changes as per you needs like class name and events.

CSS3 DIV Contenteditable with draggable

I would like to develop a website that has a div element which is content editable, and where the div element is able to be dragged around. I found the solution here, but after I coded it, it seems like I am missing some plugin, and I failed to find the plugin or framework that needed to be added into my code. Can anyone please help?
<div contenteditable="true" id="d">
<span>Text to edit</span>
</div>
$("#d").draggable()
.click(function () {
$(this).draggable({
disabled: false
});
}).dblclick(function () {
$(this).draggable({
disabled: true
});
});

Applying Events Handler to Child Elements (Event Propogation in jQuery)

Edit : Problem wasn't related Event Propagation, if you want to know how to stop propagation in jQuery, then use event.stopPropagation();
When user moves his/her mouse over <span> element my jQuery code appends an <img>into this <span> element and when he moves out his mouse off <span> than the element appended is removed. It helps people to edit the field when clicking on the appended <img> element.
The reason I used append() method to add <img> into <span> is because I want to keep <img> element visible when user moves his mouse over to appended <img> element (<img> is becoming <span>'s child element) But it didn't happen and when user moves his mouse over it <img> is being deleted. I am thinking it is because event propagation but I couldn't find how to activate it in jQuery as we do with addEventListener in Firefox based browsers.
Here is the code :
JQuery Code :
$(document).ready(function() {
$('.EditEnabled').bind("mouseover", ShowEditFields);
$(".EditEnabled").bind("mouseout", HideEditFields);
});
function ShowEditFields(event) {
$(event.target).append(" <img id='editImg' src='images/edit.png' style='margin-bottom:-3px'/>");
}
function HideEditFields(event) {
$(event.target).children("#editImg").remove();
}
Simple HTML :
<span id="something" class="EditEnabled">Something Here</span>
Can you explain my how to solve it.
Thank you.
You want to use the jQuery mouseenter and mouseleave events, not mousover and mouseout. The reason is that mouseout will fire when you move the mouse over the img.
Thankfully, jQuery combines this into a hover method:
$(document).ready(function() {
$('.EditEnabled').hover(ShowEditFields, HideEditFields);
});
However I agree with the other answer that you should use CSS to do this vs. manipulating the DOM. I would just use the :hover pseudo selector, and then add special support for IE6.
CSS
span.EditEnabled img { display: none }
span.EditEnabled:hover img,
span.EditEnabled.hover img { display: block }
Make sure you have the img in the span in your HTML to begin with, and that is all you need for most browsers and IE7+
To support IE6 add:
<!--[if lte IE 6]>
<script type="text/javascript">
$(function(){
$(".EditEnabled").hover(
function(){ $(this).addClass('hover') },
function(){ $(this).removeClass('hover')}
);
});
</script>
<![endif]-->
Firstly, I would avoid as much DOM manipulation as you can. The ideal scenario is to construct your markup like this:
<span class="editEnabled">Some data<img ...></span>
with CSS:
span.editEnabled img { display: none; }
span.editEnabled img.visible { display: inline; }
and Javascript:
$(function() {
$("span.editEnabled").hover(function() {
$(this).children("img").addClass("visible");
}, function() {
$(this).children("img").removeClass("visible");
});
});
That should pretty much do it.
I would avoid the jQuery effects as making things visible will make them block level elements rather than inline like you want.
I've found another answer actually, the way I am looking for. It might not be a best practice but at least I've found out how to solve that.
$(document).ready(function() {
// $('.EditEnabled').bind("mouseenter", ShowEditFields);
// $(".EditEnabled").bind("mouseleave", HideEditFields);
$(".EditEnabled").hover(ShowEditFields, HideEditFields);
});
function ShowEditFields(event) {
var target = $(event.target);
if (target.is(":has(#editImg)") == false)
target.append(" <img id='editImg' src='images/edit.png' style='margin-bottom:-3px;display:inline'></img>");
}
function HideEditFields(event) {
// event.stopPropagation();
// if ($(event.relatedTarget).is("#editImg") == false)
$(event.target).children("#editImg").remove();
}

Resources