Blazor WASM - statehaschanged not rerendering dropdown - c#

I have the following dropdown that holds a list of zones for my project.
<div class="col-9">
<select class="coral-input" style="width:200px" #onchange="ChangeZone" #onchange:stopPropagation="true">
#if (zones.Count > 0)
{
count = 0;
foreach (var zone in zones)
{
if (count == 0)
{
<option value="#zone" selected>#zone</option>
}
else
{
<option value="#zone">#zone</option>
}
count++;
}
}
</select>
</div>
When a page is selected by clicking on it this Task is used
private async Task PageSelected(FlyerPage p, int pIndexInList, bool propagateSelection)
{
loading = true;
// FlyerSvc.SelectPage(p);
selectedPageIndex = pIndexInList;
IsAddBlockDisabled = selectedPage == null;
try
{
if (propagateSelection)
{
_dispatcher.Dispatch(new SelectPageAction(p));
_dispatcher.Dispatch(new LoadBlocksAction(p.Id));
}
GetZones();
StateHasChanged();
}
catch
{
throw;
}
finally
{
loading = false;
}
}
My GetZones() method then does the following
private void GetZones()
{
zones.Clear();
flyerBlockZones = flyerBlocks.Where(b => b.PageId == selectedPage.Id).Where(x => x.DocumentName != null).Select(b => b.Zones).ToList();
foreach (var flyerBlockZone in flyerBlockZones.Where(z => z != null))
{
for (int i = 0; i < flyerBlockZone.Length; i++)
{
if (!zones.Contains(flyerBlockZone[i]))
zones.Add(flyerBlockZone[i]);
}
}
zones = zones.OrderBy(z => z).ToList();
flyerPageToolbar.AddZones(zones);
if (zones.Count > 0)
zone = zones[0];
else
zone = "";
ChangeZone(zone);
}
and finally this leads to my ChangeZone() method which assigns the zone in the UI
public void ChangeZone(string zone)
{
this.zone = zone;
pageDetailsComponent.ChangeZone(this.zone);
StateHasChanged();
}
The problem I am running into is that when a page is selected my dropdown does not update even when my ChangeZone() method is being used. I can't figure out why. Now I can use NavManager to just refresh and have everything reset but it would make my application look a bit clunky so I am trying to avoid that. Any help would be appreciated.

Related

Get the value of the button chosen using J-Query from MVC Razor Page?

I have created a loop in an MVC Razor Page to create the number of buttons based on a category, but have not figured out how to get the value, which is a count number and the label of the button chosen as of yet.
How do you get the value of the button and Label of the button chosen?
[Code]
//MVC Razor View Page:
//Loop to Get Dictionary List Buttons with Distinct Section Values.
for (int i = 0; i < Model.Section.Count; i++)
{
// var Count = i;
<input type="submit" name="#Html.NameFor(model => model.Section)" value=#Model.Section[i].Value id="ddlSectionButtons" , new { onclick="document.forms[0].submit();" class="ddlSectionButtons" onClick="focusMe(this);" } />
}
//Controller:
Section = (from c in entities.LocationDatas
where !string.IsNullOrEmpty(c.Section) && c.Section != null && country == c.PlantLocation
select new SelectListItem { Text = c.Section, Value = c.Section }).Distinct().ToList(),
//Model:
public List<SelectListItem> SectionList { get; set; }
public List<SelectListItem> Section { get; set; }
//J-Query: (It only gets the first button label, but not the chosen?)
//Capture the current ddlSection.
$(".ddlSectionButtons").each(function () {
$("body").on("click", ".ddlSectionButtons", function () {
var ddlSectionButtons = $('#ddlSectionButtons').val();
if ($('.ddlSectionButtons').val() != null) {
alert("Section: " + ddlSectionButtons);
};
});
});
[/Code]
J-Query only gets the first button and does not return the correct value, but only the first value, and need it to also return the count number generated through the loop.
Try to use only onclick="focusMe(this)",so that you can get the current input in the function.Here is a working demo:
for (int i = 0; i < Model.Section.Count; i++)
{
// var Count = i;
<input type="submit" name="#Html.NameFor(model => model.Section)" value=#Model.Section[i].Value id=#i class="ddlSectionButtons" onclick="focusMe(this)"/>
}
js:
function focusMe(t) {
var count=$(t).attr("id");
var ddlSectionButtons = $(t).val();
if (ddlSectionButtons != null) {
alert("Section: " + ddlSectionButtons);
}
}

Debug CSHTML Page .Net Core 2.1

I come from a .net Websites world but now I'm using .Net Core. I'm trying to find debug this code in a CSHTML file but you can't add a breakpoint? I'm using VS 2019 and trying to see more about this button which is here:
<div class="shiptype-ship" style="display: none;">
<button id="btnNext_Ship" class="btn btn-primary" disabled="disabled">Ready for Accounting Approval</button>
</div>
and it works down on this JS code in the CSHTML page:
btnNext_Ship.on('click', async function () {
divLoadingOverlay.show();
PopulateMessage(divMessage, null, null);
const uploadedPhotoCount = divImages.find('img').length;
const isUseCustomerAccount = chkUseCustomerAccount.prop('checked');
const customerAccountInfo = txtCustomerAccountInfo.val().trim();
let shippingCost_Total = 0;
let isValidInputs = true;
if (isShipType_Partial) {
const minImageCount = tblSalesOrderItems.find(`tbody tr td[name="tdSerialNos"] ul li[data-salesordershipmentdeliveryid="${salesOrderShipmentDelivery.Id}"]`).closest('tr').length;
if (minImageCount === 0) {
PopulateMessage(divMessage, 'Items must be verified first.', 'error');
isValidInputs = false;
}
else if (isRequirePhotos && uploadedPhotoCount < minImageCount) {
PopulateMessage(divMessage, 'Verified item must have at least 1 photo.', 'error');
isValidInputs = false;
}
else if (isShipType_Ship && tblSalesOrderPallets.find('tr[data-isverifyitemsincomplete="true"]').length > 0) {
PopulateMessage(divMessage, 'To deliver a pallet, all items in it must be verified.', 'error');
isValidInputs = false;
}
}
else {
const minPhotoCount = tblSalesOrderItems.find('tbody tr').length;
const salesOrderItemRows = tblSalesOrderItems.find('tbody tr');
let allItemsVerified = true;
for (let i = 0; i < salesOrderItemRows.length; i++) {
const $row = $(salesOrderItemRows[i]);
if (parseInt($row.attr('data-quantityverified')) < parseInt($row.find('td[name="tdQuantity_Picked"]').text())) {
allItemsVerified = false;
break;
}
}
if (!allItemsVerified) {
PopulateMessage(divMessage, 'Each item must be verified.', 'error');
isValidInputs = false;
}
else if (isRequirePhotos && uploadedPhotoCount < minPhotoCount) {
PopulateMessage(divMessage, 'Verified item must have at least 1 photo.', 'error');
isValidInputs = false;
}
}
if (isValidInputs) {
if (isUseCustomerAccount) {
if (customerAccountInfo.length === 0) {
PopulateMessage(divMessage, 'Customer Account Info is required.', 'error');
isValidInputs = false;
}
}
else {
shippingCost_Total = parseFloat(tblSalesOrderPallets.find('tfoot tr td input[name="txtShippingCost_Total"]').val()) || 0;
if (shippingCost_Total <= 0) {
PopulateMessage(divMessage, 'Cost per pallet or Total Cost is required.', 'error');
isValidInputs = false;
}
}
}
if (isValidInputs) {
const params = new URLSearchParams({
salesOrderShipmentId: salesOrderShipment.Id
});
const result = await fetch(`${api}LastWriteBackOn&${params}`, { credentials: 'same-origin' })
.then(response => {
if (response.ok === false) {
throw response;
}
return response.json();
})
.catch(response => {
PopulateMessage(divMessage, response.statusText || response.message, 'error');
});
if (result) {
if (result.MessageType === 'success') {
if (result.LastWriteBackOn === null) {
divStarShipNotification.attr('data-customeraccountinfo', customerAccountInfo);
divStarShipNotification.attr('data-shippingcosttotal', shippingCost_Total);
divStarShipNotification.modal('show');
}
else {
await SendToAccounting_ShipType_Ship(customerAccountInfo, shippingCost_Total);
}
}
else {
PopulateMessage(divMessage, result.Message, result.MessageType);
}
}
}
divLoadingOverlay.hide();
});
Thing is, I don't see "btnNext_Ship" in the code behind page and can't debug the cshtml page to test the JS code or how it connects to the code behind? Trying to locate a select for billing routine that's tied to this or see how it connects to this but just unable to connect the dots. Is there a way to do it? I'm looking on the web or in here and not seeing anything in relation to this? In a new job and the previous guy left before I was even hired so I'm flying solo.
Thanks!

How to check/find if a Gameobject present under a Transform is hidden or active?

I am clicking a button accordingly models display in the scene.When I click the same button again the same model appears twice.How to stop this. i.e. If model/Gameobject already loaded then no need to load again.
I am using Gameobject.find here.When I click one button models corresponding model comes and other model present in the scene disappears.At this time Gameobject.find will not work since other model is hidden.Any better solution.Please look at the code below too many if else. :)
private string _assetname;
public void LoadAsstBundles(int choice)
{
if (choice == 1)
{
_assetname = “Chair1”;
}
else if (choice == 2)
{
_assetname = “Chair2”;
}
else if (choice == 3)
{
_assetname = “Chair3”;
}
if (_assetsBundle == null)
{
Debug.Log("Could Not load AssetBundles");
}
else
{
if (GameObject.Find(_assetname + "(Clone)"))
{
Debug.Log("Already Loaded");
}
else
{
var asset = _assetsBundle.LoadAsset(_assetname);
int childcounts = ParentTransform.childCount;
Debug.Log("Asset name nw ==" + asset.name);
Debug.Log("Asset Bundles Loaded");
var go = (GameObject)Instantiate(asset, ParentTransform);
int option = go.transform.GetSiblingIndex();
int childcount = ParentTransform.childCount;
for (int i = 0; i < childcount; i++)
{
if (option == i)
{
ParentTransform.GetChild(i).gameObject.SetActive(true);
continue;
}
ParentTransform.GetChild(i).gameObject.SetActive(false);
}
}
}
}
Instead of using Find at all rather work with variables, store the references you get when instantiating the objects and reuse them later e.g.
// Here you store the reference from
// Assetbundle.LoadAsset
private object loadedAsset;
// Here you store the reference to the assets instance itself
private GameObject assetInstance;
public void LoadAsstBundles(int choice)
{
// Is _assetBundle available?
if (!_assetsBundle)
{
Debug.Log("Could Not load AssetBundles", this);
return;
}
// Was the bundle loaded before?
if (!loadedAsset)
{
loadedAsset = _assetsBundle.LoadAsset(_assetname);
if(!loadedAsset)
{
Debug.LogError("unable to load asset", this);
return;
}
Debug.Log("Asset Bundles Loaded", this);
}
// Is the object Instantiated in the scene?
if(!assetInstance)
{
assetInstance = (GameObject)Instantiate(loadedAsset, ParentTransform);
Debug.LogFormat(this, "Instantiated {0}", assetInstance.name);
}
// no need to go by names
// simply get the correct child by index
var selected = assetInstance.transform.GetChild(choice);
// Enable or disable the childs
// simply run through all childs no need to get their names etc
foreach(Transform chair in assetInstance.transform)
{
chair.gameObject.SetActive(chair == selected);
}
}
I used the Parenttransform.find to get the child hidden objects.Bit lengthy.Any updated code are welcome.
public void LoadAsstBundles(int choice)
{
if(choice==1)
{
_assetname = "Chair1";
}
else if(choice == 2)
{
_assetname = "Chair2";
}
else if(choice == 3)
{
_assetname = "Chair3";
}
if (_assetsBundle==null)
{
Debug.Log("Could Not load AssetBundles");
}
else
{
var asset= _assetsBundle.LoadAsset(_assetname);
//if (GameObject.Find(_assetname + "(Clone)"))
//{
// Debug.Log("Already Loaded");
//}
if(ParentTransform.Find(_assetname+ "(Clone)")== true)
{
Debug.Log("Already Loaded");
int childcount = ParentTransform.childCount;
for (int i = 0; i < childcount; i++)
{
if (choice == i)
{
ParentTransform.GetChild(i).gameObject.SetActive(true);
continue;
}
ParentTransform.GetChild(i).gameObject.SetActive(false);
}
}
else
{
Debug.Log("Asset Bundles Loaded");
var go = (GameObject)Instantiate(asset, ParentTransform);
int option = go.transform.GetSiblingIndex();
_loadednames.Add(go.name);
Debug.Log("Sibling index == " + go.transform.GetSiblingIndex());
int childcount = ParentTransform.childCount;
for (int i = 0; i < childcount; i++)
{
if (option == i)
{
ParentTransform.GetChild(i).gameObject.SetActive(true);
continue;
}
ParentTransform.GetChild(i).gameObject.SetActive(false);
}
}
}
}

Some rows remains in a DataGrid when deleting multiple rows

I have a WPF triggered (TextChanged) function which calls two other function whose subroutine deletes rows from a DataGrid object when certain conditions are met.
I have a feeling I might be encountering race conditions on the delete of multiple rows. When I place a MessageBox.Show("somethings'); in between the two functions, 2 rows from DataGrid are deleted as expected with the message box popping up in between delete actions.
deleteFunction("item1");
MessageBox.Show("something");
deleteFunction("item2");
However if I remove the MessageBox only the first function deletes a single row (item1)from DataGrid.
deleteFunction("item1");
deleteFunction("item2");
I have tried all sorts of ways to resolve this, Thread.Sleep(500) in between function calls, setting up a Queue to FIFO the requests, thread locking. async ... Nothing seems to work for me.
I'm not even sure it is actually a race condition issue anymore. I am starting to wonder if there is some Thread connection to the DataGrid object that the MessageBox is severing when invoked and releasing the control for another function to interact with.
Code below:
private void streamCode_TextChanged(object sender, TextChangedEventArgs e)
{
if (configurationSectionLoaded == true)
{
streamCodeAlphanumeric(streamCode.Text);
streamCodeIsChar128(streamCode.Text);
}
formEdited = true;
}
private bool streamCodeAlphanumeric(string value)
{
dataValidation dv = new dataValidation();
if (dv.isAlphanumeric(value))
{
streamCode.Background = Brushes.LightGreen;
editStreamcode.Background = Brushes.LightGreen;
editStreamcode.IsEnabled = true;
//MessageBox.Show("scE01 Deleting");
//q.Enqueue(new UILogDeleteQueue() { qEntryType = "scE01" });
try
{
UILogRemoveRow("scE01");
}
catch(Exception e)
{
MessageBox.Show(e.ToString());
}
return true;
}
else
{
editStreamcode.IsEnabled = false;
streamCode.Background = Brushes.LightPink;
UILogAddRow("scE01", "Stream Code", "Non-Alphanumeric Characters Detected!");
return false;
}
}
private bool streamCodeIsChar128(string value)
{
dataValidation dva = new dataValidation();
if (dva.isChar128(value))
{
streamCode.Background = Brushes.LightGreen;
editStreamcode.Background = Brushes.LightGreen;
editStreamcode.IsEnabled = true;
//MessageBox.Show("scE02 Deleting");
try
{
UILogRemoveRow("scE02");
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
return true;
}
else
{
editStreamcode.IsEnabled = false;
streamCode.Background = Brushes.LightPink;
UILogAddRow("scE02", "Stream Code", "Invalid Length Detected!");
return false;
}
}
Finally here is the delete row code:
private void UILogRemoveRow(string entryCode)
{
int rowCount;
rowCount = UILog.Items.Count;
if (rowCount > 0)
{
for (int i = 0; i < rowCount; i++)
{
DataGridRow row = (DataGridRow)UILog.ItemContainerGenerator.ContainerFromIndex(i);
var selectedItem = UILog.ItemContainerGenerator.ContainerFromIndex(i);
if (row != null)
{
UILogObject theItem = (UILogObject)row.DataContext;
if (theItem.entryType == entryCode)
{
UILog.Items.RemoveAt(i);
}
}
}
}
}
Any assistance would be greatly appreciated.
UPDATE: included UILogAddRow function
private void UILogAddRow(string entryCode, string entryIdentifier, string entryDetail)
{
bool itemExists = false;
int rowCount;
rowCount = UILog.Items.Count;
if (rowCount > 0)
{
for (int i = 0; i < rowCount; i++)
{
DataGridRow row = (DataGridRow)UILog.ItemContainerGenerator.ContainerFromIndex(i);
if (row != null)
{
UILogObject theItem = (UILogObject)row.DataContext;
if (theItem.entryType == entryCode)
{
itemExists = true;
}
}
}
}
else
{
//MessageBox.Show(rowCount.ToString());
}
if (itemExists != true)
{
UILog.Items.Add(new UILogObject() { entryType = entryCode, identifier = entryIdentifier, detail = entryDetail });
}
UILog.Items.Refresh();
}
instead of working with low-level container elements (DataGridRow), cast items to your known type, and then search and remove
private void UILogRemoveRow(string entryCode)
{
var item = UILog.Items.OfType<UILogObject>()
.FirstOrDefault(x => x.entryType == entryCode);
if (item != null)
UILog.Items.Remove(item);
}

using c# remove duplicate html span elements

I have to convert word to html which I'm doing with Aspose and that is working well. The problem is that it is producing some redundant elements which I think is due to the way the text is store in word.
For example in my word document the text below appears:
AUTHORIZATION FOR RELEASE
When converted to html it becomes:
<span style="font-size:9pt">A</span>
<span style="font-size:9pt">UTHORIZATION FOR R</span>
<span style="font-size:9pt">ELEASE</span>
I'm using C# and would like a way to remove the redundant span elements. I'm thinking either AngleSharp or html-agility-pack should be able to do this but I'm not sure this is the best way?
What I wound up doing is iterating over all the elements and when adjacent span elements were detected I concatenated the text together. Here is some code if others run into this issue. Note code could use some cleanup.
static void CombineRedundantSpans(IElement parent)
{
if (parent != null)
{
if (parent.Children.Length > 1)
{
var children = parent.Children.ToArray();
var previousSibling = children[0];
for (int i = 1; i < children.Length; i++)
{
var current = children[i];
if (previousSibling is IHtmlSpanElement && current is IHtmlSpanElement)
{
if (IsSpanMatch((IHtmlSpanElement)previousSibling, (IHtmlSpanElement)current))
{
previousSibling.TextContent = previousSibling.TextContent + current.TextContent;
current.Remove();
}
else
previousSibling = current;
}
else
previousSibling = current;
}
}
foreach(var child in parent.Children)
{
CombineRedundantSpans(child);
}
}
}
static bool IsSpanMatch(IHtmlSpanElement first, IHtmlSpanElement second)
{
if (first.ChildElementCount < 2 && first.Attributes.Length == second.Attributes.Length)
{
foreach (var a in first.Attributes)
{
if (second.Attributes.Count(t => t.Equals(a)) == 0)
{
return false;
}
}
return true;
}
return false;
}

Categories

Resources