Blazor drag and drop how to get target object? - drag-and-drop

I can't seem to figure out the right way to get the target object. Here is the code front end code that is supposed to have drag and drop functionality:
<div class="pos-top">
<div id="imgGrid" class="grid bg-white" style="grid-template-columns:repeat(#columnCount, #(unitWidth)); grid-auto-flow:dense;">
#foreach (var b in blocks)
{
#if ((b.Placement[_pageType].Visible == true || showHiddenBlocks == true) && b.Zones != null && b.Zones.Contains(zone))
{
var id = b.Id;
<div class="col-span-#b.ColSpan row-span-#b.RowSpan relative border border-black box-border #(b.isDragOver?"dropped":"")" style=" order:#b.Placement[_pageType].Order;" #ondblclick="(() => ChangeBlockProperties(b))"
draggable="true"
data-block-id="#b.Id"
id="#id" #ondrop="#((e) => ondropOver(b, blocks.ToList()))"
ondragover="event.preventDefault();"
#ondragstart="#((e) => ondragstart(e, b, blocks.ToList()))"
#ondragenter="#(() => ondragenter(b))"
#ondragleave="#(() => { b.isDragOver = false; })"
#ondragend="#(() => ondragend(b, blocks.ToList()))">
<div class="blockNumberInfo absolute rounded-full bg-red-700 flex justify-center items-center border-2 border-black"
style="width:40px;height:20px">
#b.LocalIndex / #b.Placement[_pageType].Order
</div>
</div>
}
}
</div>
}
}
</div>
This is my code that is moving the blocks around:
public async void ondropOver(FlyerBlock item, List<FlyerBlock> flyerBlocks)
{
DragEnter = null;
if (DraggedItem == null) return;
if (DraggedItem == item) return;
DraggedItem.Placement[_pageType].Order = item.Placement[_pageType].Order;
await BlockplacementEditService.SaveBlockChangesAsync(flyerBlocks, DraggedItem, DraggedItem.Placement[_pageType].Order, _pageType, zone);
DraggedItem = null;
item.isDragOver = false;
//StateHasChanged();
}
public void ondragstart(DragEventArgs e, FlyerBlock item, List<FlyerBlock> flyerBlocks)
{
e.DataTransfer.EffectAllowed = "move";
DraggedItem = item;
DraggedItemPosition = item.Placement[_pageType].Order;
}
public void ondragenter(FlyerBlock item)
{
item.isDragOver = true;
DragEnter = item;
}
public async void ondragend(FlyerBlock item, List<FlyerBlock> flyerBlocks)
{
item.isDragOver = false;
if (DraggedItem == null) return;
DragEnter = null;
// item.isDragOver = true;
}
The issue I am running into is that I dont know how to pass the targetblock into my drop over event. I tried using DragEventArgs but that does not work I have also tried using jsruntime but I can only extract the dragged block. I want to be able to get the target block so I can update the order correctly. Any help would be appreciated!

Related

Writing new EF core entities does not use the auto_increment but writes 0 value as ID

I'm currently programming a modal to add some basic information to print an invoice with that information later on. The code is still messy but as soon as i figure out how to solve my problem, I'm going to smarten up the code a little bit.
I'm currently struggling in creating some input fields that are used to add or remove the items of the invoice. Currently it looks like that:
When I open that modal, I retrieve the OrderSpecifications (that's what I call these lines) from the DB and populate the input fields.
protected override void OnInitialized()
{
specs = nfzContext.OrderSpecifications.Where(x => x.FkOrderNumber == order.Id).ToList();
numberOfSpecLines = nfzContext.OrderSpecifications.Where(x => x.FkOrderNumber == order.Id).Count();
SetupSpeclines();
}
I have 5 input fields predefined, which are only hidden in case there are no specification lines already existing. If i press the + button, I show the a new line.
<div class="card-body">
<div class="form-group">
<div class="row">
<div class="col">
<input class="form-control" type="text" #bind="specification1.ItemName" hidden="#specLine1Disabled" placeholder="Zeile 1" />
</div>
</div>
<div class="row">
<div class="col">
<input class="form-control" type="text" #bind="specification2.ItemName" hidden="#specLine2Disabled" placeholder="Zeile 2" />
</div>
</div>
</div>
</div>
The SetupSpecline method grabs the existing speclines and adds a reference for each to one of the five specification1 ... specification5 variables:
void SetupSpeclines() {
if (numberOfSpecLines <= 1) {
specLine1Disabled = false;
if (numberOfSpecLines == 1) specification1 = specs.ElementAt(0);
numberOfVisibleSpecLines = 1;
}
else if (numberOfSpecLines == 2) {
specLine1Disabled = false;
specLine2Disabled = false;
specification1 = specs.ElementAt(0);
specification2 = specs.ElementAt(1);
numberOfVisibleSpecLines = 2;
}
else if (numberOfSpecLines == 3) {
specLine1Disabled = false;
specLine2Disabled = false;
specLine3Disabled = false;
specification1 = specs.ElementAt(0);
specification2 = specs.ElementAt(1);
specification3 = specs.ElementAt(2);
numberOfVisibleSpecLines = 3;
}
else if (numberOfSpecLines == 4) {
specLine1Disabled = false;
specLine2Disabled = false;
specLine3Disabled = false;
specLine4Disabled = false;
specification1 = specs.ElementAt(0);
specification2 = specs.ElementAt(1);
specification3 = specs.ElementAt(2);
specification4 = specs.ElementAt(3);
numberOfVisibleSpecLines = 4;
}
else if (numberOfSpecLines == 5) {
specLine1Disabled = false;
specLine2Disabled = false;
specLine3Disabled = false;
specLine4Disabled = false;
specLine5Disabled = false;
specification1 = specs.ElementAt(0);
specification2 = specs.ElementAt(1);
specification3 = specs.ElementAt(2);
specification4 = specs.ElementAt(3);
specification5 = specs.ElementAt(4);
numberOfVisibleSpecLines = 5;
}
}
This it the database model for OrderSpecification (ID = primary key):
namespace MyNamespace
{
public class OrderSpecification
{
public OrderSpecification();
public int Id { get; set; }
public int FkOrderNumber { get; set; }
public int SeqId { get; set; }
public string ItemName { get; set; }
public virtual Order FkOrderNumberNavigation { get; set; }
}
}
You can unhide (+) up to five inputs and enter some data. After you press the OK button, the routine starts to check if individual lines have a) altered (=ItemName changed), if new ones were added or if some were removed (=empty input):
void Confirm()
{
List<OrderSpecification> linesToAdd = new List<OrderSpecification>();
List<OrderSpecification> linesToRemove = new List<OrderSpecification>();
if (!string.IsNullOrEmpty(specification1.ItemName))
{
// Check if there is a spec at index 0
if (specs.ElementAtOrDefault(0) != null)
{
specs.ElementAtOrDefault(0).ItemName = specification1.ItemName; // Only itemName has changed
}
else
{ // Add new line
linesToAdd.Add(new OrderSpecification { FkOrderNumber = order.Id, ItemName = specification1.ItemName, SeqId = 1 });
}
}
else if (!string.IsNullOrEmpty(specification1.ItemName) && specs.ElementAtOrDefault(0) != null)
Now, while all that works just fine, I have trouble writing the new speclines to the database. For example, When i run
foreach (var spec in LinesToAdd)
{
nfzContext.Add(spec);
}
nfzContext.SaveChanges();
I get the error message
{"Cannot insert explicit value for identity column in table
'OrderSpecifications' when IDENTITY_INSERT is set to OFF."}
What I assume is that EF Core tries to add the new OrderSpecification with the ID=0, which is the standard value when creating a new OrderSpecification element. I need to tell EF Core to not write the ID as 0 but to let the database set the value by using auto_increment.
And what's odd is, although I have assigned the Primary Key to the ID field, when I scaffold, the key is not set in the modelbuilder:
modelBuilder.Entity<OrderSpecification>(entity =>
{
entity.ToTable("OrderSpecifications", "samnfz");
entity.Property(e => e.Id).HasColumnName("ID");
entity.Property(e => e.FkOrderNumber).HasColumnName("FK_OrderNumber");
entity.Property(e => e.ItemName).IsRequired();
entity.Property(e => e.SeqId).HasColumnName("SeqID");
entity.HasOne(d => d.FkOrderNumberNavigation)
.WithMany(p => p.OrderSpecifications)
.HasForeignKey(d => d.FkOrderNumber)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_OrderSpecifications_Orders");
});
Any idea?
Ugh, I think I have found the error. After analyzing the table structure in the modelbuilder, I recognized that the structure is not the same that I have in my database. So i scaffolded once again and the error is gone. obviously, I used model types that were not current and maybe the primary key was set to another attribute...

Vaadin Grid always selects last row

I need help debugging the follow issue:
When I click on a Vaadin Grid with 3 rows, it ignores the click on any but the last row and always selects the 3rd row.
Code is as follows:
// declare Grid objects
public final Grid<SoapKPIContainer> soapKPIOverviewGridDisplay;
..
public SoapKPIOverviewView(SoapKPIRepository soapKPIRepository, Navigator navigator,
BpspSoapCheckCommunications bpspSoapCheckCommunications,
UIMessageByLocaleService messageByLocaleService) {
..
this.soapKPIOverviewGridDisplay = new Grid<>(SoapKPIContainer.class);
this.soapKPIOverviewGridDisplay.setColumns();
Grid.Column<SoapKPIContainer, ?> lastAlarmStatusIconColumn = this.soapKPIOverviewGridDisplay.addColumn("lastAlarmStatusIcon", new ImageRenderer<>());
lastAlarmStatusIconColumn.setSortable(false);
lastAlarmStatusIconColumn.setResizable(false);
lastAlarmStatusIconColumn.setWidth(80.0f);
lastAlarmStatusIconColumn.setCaption(messageByLocaleService.getMessage("label.lastalarmstatus"));
Grid.Column<SoapKPIContainer, ?> activationIconColumn = this.soapKPIOverviewGridDisplay.addColumn("activationIcon", new ImageRenderer<>());
activationIconColumn.setSortable(false);
activationIconColumn.setResizable(false);
this.soapKPIOverviewGridDisplay.getDefaultHeaderRow().getCell("lastAlarmStatusIcon").setHtml(messageByLocaleService.getMessage("label.lastalarmstatus"));
this.soapKPIOverviewGridDisplay.getDefaultHeaderRow().getCell("activationIcon").setHtml(messageByLocaleService.getMessage("label.activationicon"));
this.soapKPIOverviewGridDisplay.addColumn(SoapKPIContainer::getKpiName).
setCaption(messageByLocaleService.getMessage("header.kpiName"));
..
this.setSizeFull();
this.soapKPIOverviewGridDisplay.setSizeFull();
this.soapKPIOverviewGridDisplay.setHeight(400, Unit.PIXELS);
this.soapKPIService = new SoapKPIService(soapKPIRepository);
this.soapKPIOverviewGridDisplay.setItems( soapKPIService.toContainer( soapKPIService.findAllSoapKPI() ) );
..
// adding Listener for the Grid to enable for the user to select single KPIs
soapKPIOverviewGridDisplay.setSelectionMode(SelectionMode.SINGLE);
soapKPIOverviewGridDisplay.asSingleSelect().addValueChangeListener(e -> {
log.debug("asSingleSelect().addValueChangeListener " + e.getValue());
if ( e.getValue() != null) {
log.debug("asSingleSelect().addValueChangeListener findSoapKPIById #" + e.getValue().getKpiId());
testKPIDefView.setEnabled(true);
soapKPI = soapKPIService.findSoapKPIById( e.getValue().getKpiId() );
changeEnabled.setVisible(true);
if( soapKPI.getEnabled() == 1)
changeEnabled.setCaption(messageByLocaleService.getMessage("button.disable"));
else
changeEnabled.setCaption(messageByLocaleService.getMessage("button.enable"));
}
else {
testKPIDefView.setEnabled(false);
changeEnabled.setVisible(false);
soapKPI = null;
}
});
..
soapKPIOverviewLayout.addComponent(soapKPIOverviewGridDisplay);
I'm still not sure what line in the code cause it to break, but I found that overriding the equals method of the row object makes the problem go away:
#Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof SoapKPIContainer)) {
return false;
}
SoapKPIContainer container = (SoapKPIContainer) o;
return this.getKpiId() == container.getKpiId();
}

How to remove elements from GXT HtmlLayoutContainer

I have the following Widget that uses GXT HtmlLayoutContainer:
public class MyWidget implements IsWidget {
public interface MyWidgetLayout extends XTemplates {
#XTemplate(source = "my/stuff/resources/MyWidget.html")
SafeHtml getTemplate(List<MyData> myData);
}
public static final MyWidgetLayout LAYOUT = GWT.create(MyWidgetLayout .class);
private final List<MyData> myData;
private HtmlLayoutContainer container;
public TaskRegulationsContainer(List<MyData> myData) {
this.myData = myData;
}
#Override
public Widget asWidget() {
if (container == null) {
container = new HtmlLayoutContainer(LAYOUT.getTemplate(regulations, postfix));
if (null != regulations) {
for (MyData d : myData) {
MyOtherWidget w = new MyOtherWidget(d);
container.add(w, new AbstractHtmlLayoutContainer.HtmlData(".my-data-" + myData.getUniqueId()));
}
}
}
return container;
}
public void handleRemovedData(MyData removedData) {
// How can I remove the widget corresponding to removedData
// with the selector my-data-{uniqueId}?
}
}
with the following template:
<style>
</style>
<div>
<span>My Data:</span>
<div>
<tpl for="myData">
<div class="my-data-{uniqueId}"></div>
</tpl>
</div>
</div>
How can I remove individual myData list items from the UI after the template is rendered?
You can iterate over the children of the container, check if the class attribute contains "my-data-" + uniqueId and delete it.
Something like this should work:
public void handleRemovedData(MyData removedData) {
for (int i = 0; i < container.getChildCount(); i++) {
node = pParent.getChild(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node.cast();
if (element.getClassName().contains("my-data-" + removedData.getUniqueId())) {
container.removeChild(element);
}
}
}
}
Hope that helps.

Breadcrumb in AEM 6

I have a requirement to create breadcrumb in sightly. I have following code which is working fine in JSP. But i am struggling to convert the code to sightly because i am not getting the right methods in currentStyle object to get the "absParent" and others. Any help will be highly appreciated!!
<%# include file="/libs/foundation/global.jsp" %>
<%
final int startLevel = currentStyle.get("absParent", 3);
final int endLevel = currentPage.getDepth() - currentStyle.get("relParent", 0);
final int minItems = currentStyle.get("minItems", 2);
if (startLevel <= endLevel - minItems) {
%><section class="breadcrumbs"><%
for (int level = startLevel+1; level < endLevel; ++level) {
Page itemPage = currentPage.getAbsoluteParent(level);
if (itemPage == null || !itemPage.isValid() || itemPage.isHideInNav()) {
continue;
}
final String pagePath = itemPage.getPath() + ".html";
final String pageTitle = itemPage.getNavigationTitle();
String className = "breadcrumb-item-"+level;
if (level == startLevel) className += " breadcrumb-first";
if (level == endLevel-1) className += " breadcrumb-last";
pageContext.setAttribute("className", className);%>
<section class="breadcrumbs ">
<%= xssAPI.encodeForHTML(pageTitle) %>
</section>
<%} %>
</section><%
}
%>
To create breadcrumb you have to write a WCMuse class and include that in this component.
<div
data-sly-use.breadcrumb="${'com.mySite.components.BreadcrumbUse'}">
<!-- + Breadcrumb component + -->
<div class="breadcrumb component">
<div class="breadcrumb_nav_bar clearfix"
data-sly-test="${breadcrumb.navList}"
data-sly-list.element="${breadcrumb.navList}">
<p data-sly-test="${!elementList.last}">
<a href="${element.path}.html">${element.title ||
element.navigationTitle || element.name}</a>
</p>
<p data-sly-test="${elementList.last}">${element.title ||
element.navigationTitle || element.name}</p>
</div>
</div>
<!-- - Breadcrumb component - -->
</div>
Code Sample for WCMUse class:
Public class BreadcrumbUse extends WCMUse
{
private List<Page> navList = new ArrayList<Page>();
#Override
public void activate() throws Exception
{
setBreadCrumbItems();
}
private void setBreadCrumbItems()
{
long level = 4L;
long endLevel = 1L;
int currentLevel = getCurrentPage().getDepth();
while (level < currentLevel - endLevel)
{
Page trailPage = getCurrentPage().getAbsoluteParent((int) level);
if (trailPage == null)
{
break;
}
this.navList.add(trailPage);
level++;
}
}
public List<Page> getNavList()
{
return this.navList;
}
}
The below code will work for creating breadcrumbs in AEM6.2 using Javascript and HTL(previously sightly).It worked well for me..here we go
Javascript to be used in the server side script(it can also be created using java)
script.js
use(function () {
var title = currentPage.getTitle();
//To get the title of the current page
var level = currentPage.getDepth();
//To find the depth of the current page from the root
var cts = new Array();
// To store the traversed page (object) from the root
for(var i=1;i<level;i++)
{ // Here I used i=1 for mycase(i=0 will be /content)
var titl = currentPage.getAbsoluteParent(i);
//To get the absolute parent at each level from root
pageStack.push(titl);
//Stack to maintain the pages
}
return {
title: title,
pageStack:pageStack
};
});
Breadcrumbs.html
<sly data-sly-use.cpt="script.js">
<h1>${cpt.title}</h1>
<div data-sly-list="${cpt.pageStack}">
<span> ${item.title}/</span>
</div>
</div>
Thus we get the breadcrumbs ready for our presentation!!!

Customise Validation summary

I have used html.ValidationSummary to get all errors displayed on top of the page.
This will render list with errors on top of the page.
Example:
<ul>
<li>UserName is invalid</li>
</ul>
I have how ever need to render every item instead of list as custom div with additional html tags inside.
I need every line to be rendered as short example below (this is only one line):
<div>
<div class="right"><a href="#closeError">Close error</div>
<div class="right"><a href="#Update">Update Field</div>
<label>Error:</label> Name on the page is invalid.
</div>
What is your opininon how to achieve this rendering?
I have considered to create html helper where i will take ModelState and get all errors, but not sure this will work...
I have considered to create html helper where i will take ModelState and get all errors, but not sure this will work...
Why wouldn't that work?
public static class ValidationExtensions
{
public static IHtmlString MyValidationSummary(this HtmlHelper htmlHelper)
{
var formContext = htmlHelper.ViewContext.ClientValidationEnabled
? htmlHelper.ViewContext.FormContext
: null;
if (formContext == null && htmlHelper.ViewData.ModelState.IsValid)
{
return null;
}
var sb = new StringBuilder();
var htmlSummary = new TagBuilder("div");
var modelStates = htmlHelper.ViewData.ModelState.Values;
sb.AppendLine("<div class=\"right\"><a href=\"#closeError\">Close error</div>");
sb.AppendLine("<div class=\"right\"><a href=\"#Update\">Update Field</div>");
if (modelStates != null)
{
foreach (ModelState modelState in modelStates)
{
foreach (ModelError modelError in modelState.Errors)
{
var userErrorMessageOrDefault = GetUserErrorMessageOrDefault(modelError);
if (!string.IsNullOrEmpty(userErrorMessageOrDefault))
{
sb.AppendFormat("<label>Error:</label> {0}{1}", htmlHelper.Encode(userErrorMessageOrDefault), Environment.NewLine);
}
}
}
}
htmlSummary.InnerHtml = sb.ToString();
if (formContext != null)
{
formContext.ReplaceValidationSummary = true;
}
return MvcHtmlString.Create(htmlSummary.ToString(TagRenderMode.Normal));
}
private static string GetUserErrorMessageOrDefault(ModelError error)
{
if (!string.IsNullOrEmpty(error.ErrorMessage))
{
return error.ErrorMessage;
}
return null;
}
}
and then:
<%= Html.MyValidationSummary() %>