Blazor drag and drop event preventDefault() does not exist - javascript

I am writing code to move some blocks around a grid using drag and drop. This is the block element:
<div class="col-span-#b.ColSpan row-span-#b.RowSpan relative border border-black box-border"
style="order:#b.Placement[_pageType].Order;"
#ondblclick="(() => ChangeBlockProperties(b))"
#ondragstart="#(() => DragStart(b))"
#ondragover="#((DragEventArgs e) => DragOver(e))"
#ondrop="#((DragEventArgs e) => Drop(e, b))">
And this is the code I have written for it:
private async Task DragStart(FlyerBlock block)
{
await js.InvokeVoidAsync("startDrag", block);
}
private async Task DragOver(DragEventArgs e)
{
e.PreventDefault();
}
private async Task Drop(DragEventArgs e, FlyerBlock targetBlock)
{
e.PreventDefault();
var data = await js.InvokeAsync<string>("getDraggedBlock");
var sourceBlock = JsonConvert.DeserializeObject<FlyerBlock>(data);
// Swap the targetBlock and sourceBlock's placement
var tempOrder = targetBlock.Placement[_pageType].Order;
targetBlock.Placement[_pageType].Order = sourceBlock.Placement[_pageType].Order;
sourceBlock.Placement[_pageType].Order = tempOrder;
// Save the changes to the database
await BlockManager.UpdateBlock(targetBlock);
}
Both in dragover and Drop my e.PreventDefault(); is giving me the following error: "DragEventArgs does not contain a definition for 'PreventDefault'. I am pretty sure this should be working I can't figure out why it would be giving me an error. Any help would be appreciated.

Well I figured out how to fix it because David gave me a hint about calling a method that didn't exist. I replaced e.PreventDefault(); with await js.InvokeVoidAsync("preventDefault", e); and just used my jsruntime. Thanks all!

Related

Run Js function only once after 2 seconds from c# code behind

Hello i have the next question, ive got the next function =
protected void lnk_Click( object sender, EventArgs e )
{
LinkButton btn = sender as LinkButton;
string text = btn.CommandName;
ScriptManager.RegisterStartupScript( this, GetType(), "script", "alert('"+ text + "');", true );
}
I want to run the function after a second or 1.5 secs because this is running before the page renders visually, causing a "visual bug" on which the li tags (for example) dont get the css properties.
Any suggestion would help, thanks!
The JavaScript content should run on the event DOMContentLoaded like this:
document.addEventListener("DOMContentLoaded", function(){alert('text');});
If you're sure you want to use the "dirty" way, use setTimeout:
setTimeout(function(){alert('text');}, 1500); // 1500 milliseconds
In async you can wait using Task.Delay
private async Task<Response> ExecuteTask(Request request)
{
var response = await GetResponse();
switch(response.Status)
{
case ResponseStatus.Pending:
await Task.Delay(TimeSpan.FromSeconds(2))
response = await ExecuteTask(request);
break;
}
return response;
}

My Buttons are not working after using fetch api along with express.js

I have strange problem with buttons that are requesting for displaying templates on client page.
This is client side code. The main task of entire class is to just enable user to click button, send request and get response with HTML that has been rendered from handlebars template and just paste it in partiuclar place on client side. It works, but only once. After first click and displaying elements, I totally lose any interaction with those buttons. There is no request, and there is no even EventListener for clicking. I get no error. Completely there is no single reaction after clicking.
class Weapons {
constructor() {
this.buttons = document.querySelectorAll('.type')
}
async displayWeapon(path) {
const container = document.querySelector('.shop-container')
await fetch(`weapons/${path}`).then(response => response.json()).then(data => container.innerHTML += data);
}
chooseWeapon() {
this.buttons.forEach(btn => {
btn.addEventListener('click', (e) => {
console.log('click');
let weaponType = e.target.dataset.type
switch (weaponType) {
case 'pistols':
console.log('click');
return this.displayWeapon(weaponType)
case 'rifles':
console.log('click');
return this.displayWeapon(weaponType)
case 'grenades':
console.log('click');
return this.displayWeapon(weaponType)
case 'closerange':
console.log('click');
return this.displayWeapon(weaponType)
case 'rocketlauchner':
console.log('click');
return this.displayWeapon(weaponType)
}
})
})
}
}
document.addEventListener('DOMContentLoaded', function () {
const weapons = new Weapons();
weapons.chooseWeapon();
> When I invoke displayWeapon(path) here it also works, but immidiately
> after displaying html elements clicking on buttons again does not
> initiate any action.
})
Here is app.get function but I doubt it's source of problem.
app.get('/weapons/:id', (req, res) => {
console.log('req');
console.log(req.url);
let type = req.params.id;
res.render(type, function (err, html) {
res.json(html);
})
})
Ok. The answer is actually simple. In fetch function container.innerHTML += data. This line deletes my html with buttons, and the same time it deletes eventListeners. So I need just to modify my html.

Does anyone know why this code is not working the way I want it to?

I am creating a web app with node.js, express and pug templates and here I am trying to simulate a warning when the user tries to remove a review he has posted.
so, in the front end I have a button that the user clicks to remove his review
when the user clicks that button I run
index.js
import { showWarning } from './warning';
const removerStoreReviewBtn = document.querySelector('.side-nav__removeStoreReviewbtn');
if (removerStoreReviewBtn)
removerStoreReviewBtn.addEventListener('click', e => {
e.preventDefault();
showWarning('Would you like to remove this review ?');
});
warning.js
export const hideWarning = () => {
const el = document.querySelector('.warning');
const warningText = document.querySelector('.warning__text');
if (el) el.parentElement.removeChild(el);
if (warningText) warningText.parentElement.removeChild(warningText);
};
export const showWarning = (msg, time = 30) => {
hideWarning();
console.log(msg);
const markUp = `
<div class="warning">
<div class="warning__text">${msg}</div>
<button class="warning--no">
<span>Cancelar</span>
</button>
<button class="warning--yes">
<span>Apagar</span>
</button>
</div>`;
document.querySelector('.header').insertAdjacentHTML('afterend', markUp);
window.setTimeout(hideWarning, time * 1000);
};
The showWarning function display everything the way I want in the front end
then back at the index.js file I have the following code
index.js
const warningBtnYes = document.querySelector('.warning--yes');
const warningBtnNo = document.querySelector('.warning--no');
if (warningBtnYes)
warningBtnYes.addEventListener('click', e => {
e.preventDefault();
console.log('remove');
//removerStoreReview(reviewId);
});
if (warningBtnNo)
warningBtnNo.addEventListener('click', e => {
e.preventDefault();
console.log('Do not remove');
});
when I click any of these buttons nothing happens (I am expecting the console.logs) and I can't figure out why nothing happens, hopefully anyone can help me.
Thanks
Mateus
When you use .parentElement.removeChild() you have turned off all event listeners for those button.
You have two options. You can preserve the event listeners by storing the return value from the .removeChild() call. In order to restore the event listeners you will need to reuse the stored (previously removed) node.
Alternatively, you'll need to re-add your event listeners after inserting the new HTML.
Helpful docs

Add keyboard-event to Openlayers map

I'm unable to add a custom keyboard-event to Openlayers, and can't figure out why. Might it be a bug in relation to the already existing keyboard-events included in Openlayers?
I've tried the following with no result:
this.map.getViewport().addEventListener('keydown', (e) => {
console.log(e);
}, true)
document.getElementById('map').addEventListener('keydown', (e) => {
console.log(e);
})
Listening to clicks on the same elements work fine:
this.map.getViewport().addEventListener('click', (e) => {
console.log(e);
}, true)
document.getElementById('map').addEventListener('click', (e) => {
console.log(e);
})
Any solutions to this?
As mentioned map needs focus. You can use the FocusMap interaction of ol-ext to focus on the map when ckick on it.
See https://github.com/Viglino/ol-ext/blob/master/src/interaction/FocusMap.js
This example use it to handle ctrl+c/ctrl+v on a map.
https://viglino.github.io/ol-ext/examples/interaction/map.interaction.copypaste.html
This problem as Mike mentioned is occurring because of focus issues.
I faced this problem a few months ago, so I searched my old projects and find this:
<div id="map" tabindex="0"></div>
After assigning a tab index to an element you can use javascript focus().
in order to use it (after assigning tab index) use this:
document.getElementById('map').focus();
I think this could help.
Also, there is an answer I found months ago is here. You can find more info about focusing.
The most reliable solution in our angular application was to add a custom Interaction, but you still need to set tabindex="0" on your map ;)
<div class="map" tabindex="0" id="map"></div>
Here is an example:
import { Interaction } from "ol/interaction";
import { MapBrowserEvent } from "ol";
class KeyboardEventInteraction extends Interaction {
constructor() {
super();
}
handleEvent(mapBrowserEvent: MapBrowserEvent<KeyboardEvent>) {
let stopEvent = false;
if (mapBrowserEvent.type === "keydown") {
const keyEvent = mapBrowserEvent.originalEvent;
if (keyEvent.code?.toLowerCase() === "escape") {
// do whatever you want with your escape key
stopEvent = true;
}
// add other keys
if (stopEvent) {
keyEvent.preventDefault();
}
}
return !stopEvent;
}
}
You need to add this handler to your map:
new Map({
//... your map settings
interactions: [
//... your interactions
new KeyboardEventInteraction(),
],
});

Catching all audio end events from dynamic content in jquery

I have seen similar questions - but not that fix my problem!
I have audio on my page and when one ends, I want the next to start, but I can't even get the ended to trigger...
I cut the code down to this:
function DaisyChainAudio() {
$().on('ended', 'audio','' ,function () {
alert('done');
});
}
This is called from my page/code (and is executed, setting a break point shows that).
As far as I understand this should set the handler at the document level, so any 'ended' events from any 'audio' tag (even if added dynamically) should be trapped and show me that alert...
But it never fires.
edit
With some borrowing from Çağatay Gürtürk's suggestion so far have this...
function DaisyChainAudio() {
$(function () {
$('audio').on('ended', function (e) {
$(e.target).load();
var next = $(e.target).nextAll('audio');
if (!next.length) next = $(e.target).parent().nextAll().find('audio');
if (!next.length) next = $(e.target).parent().parent().nextAll().find('audio');
if (next.length) $(next[0]).trigger('play');
});
});
}
I'd still like to set this at the document level so I don't need to worry about adding it when dynamic elements are added...
The reason it does not fire is, media events( those specifically belonging to audio or video like play, pause, timeupdate, etc) do not get bubbled. you can find the explanation for that in the answer to this question.
So using their solution, I captured the ended event, and this would allow setting triggers for dynamically added audio elements.
$.createEventCapturing(['ended']); // add all the triggers for which you like to catch.
$('body').on('ended', 'audio', onEnded); // now this would work.
JSFiddle demo
the code for event capturing( taken from the other SO answer):
$.createEventCapturing = (function () {
var special = $.event.special;
return function (names) {
if (!document.addEventListener) {
return;
}
if (typeof names == 'string') {
names = [names];
}
$.each(names, function (i, name) {
var handler = function (e) {
e = $.event.fix(e);
return $.event.dispatch.call(this, e);
};
special[name] = special[name] || {};
if (special[name].setup || special[name].teardown) {
return;
}
$.extend(special[name], {
setup: function () {
this.addEventListener(name, handler, true);
},
teardown: function () {
this.removeEventListener(name, handler, true);
}
});
});
};
})();
Try this:
$('audio').on('ended', function (e) {
alert('done');
var endedTag=e.target; //this gives the ended audio, so you can find the next one and play it.
});
Note that when you create a new audio dynamically, you should assign the events. A quick and dirty solution would be:
function bindEvents(){
$('audio').off('ended').on('ended', function (e) {
alert('done');
var endedTag=e.target; //this gives the ended audio, so you can find the next one and play it.
});
}
and run bindEvents whenever you create/delete an audio element.

Categories

Resources