How to enlist children of specified Parent in treeview colum (table) - grails-plugin

I am newbie in grails and tried to implement treeview using RichUI plugin, which shows all parents with individual children in Parent.list.gsp
xml for parent and their children
<parents name='Parents'>
<Parent id='1' name='Parent_1'>
<Children name='Children'>
<child name='Child_2' id='2' />
<child name='Child_4' id='4' />
<child name='Child_1' id='3' />
<child name='Child_3' id='1' />
</Children>
</Parent>
<Parent id='2' name='Parent_2'>
<Children name='Children'>
<child name='Child_1' id='8' />
<child name='Child_2' id='7' />
<child name='Child_4' id='6' />
<child name='Child_3' id='5' />
</Children>
</Parent>
</parents>
Parent Domain Class
class Parent {
String name
static hasMany = [children:Child]
}
Child Domain Class
class Child {
String name
Parent parent
static belongsTo = [parent:Parent]
}
Parent Controller
def list = {
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.parents(name: "Parents"){
Parent.list().each {
Parent parentt = it
Parent( id:parentt.id,name:parentt.name) {
Children(name:'Children'){
parentt.children.each {
Child childd = it
child(name:childd.name,id:childd.id)
}
}
}
}
}
if(!params.max)params.max=10
["data":writer.toString(),parentInstanceList: Parent.list(params), parentInstanceTotal: Parent.count()]
}
Parent.list.gsp
<head>
<resource:treeView/> ...</head>
<body>
<table>
<thead>
<tr>
<g:sortableColumn property="id" title="${message(code: 'parent.id.label', default: 'Id')}" />
<g:sortableColumn property="name" title="${message(code: 'parent.name.label', default: 'Name')}" />
<g:sortableColumn property="relationship" title="${message(code: 'parent.relationhsip.label', default: 'Relationship')}" />
</tr>
</thead>
<tbody>
<g:each in="${parentInstanceList}" status="i" var="parentInstance">
<tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
<td><g:link action="show" id="${parentInstance.id}">${fieldValue(bean: parentInstance, field: "id")}</g:link></td>
<td>${fieldValue(bean: parentInstance, field: "name")}</td>
<td><richui:treeView xml="${data}" /></td>
</tr>
</g:each>
</tbody>
</table>
</body>
Problem
Currently, in list view, every Parent entry has list of all parents and their children under
relationship column
Parent List view Snapshot link text
Question
how can i enlist all children only for each parent instead of enlisting all parents with their children in each Parent entry ?
thanks in advance
Rehman

the problem here is you are rendering the XML for all the nodes in one operation and then passing it to 'data' which displays the same XML for every row.
what you need to do is pass a parameter of the parent id into the closure:
/* this gets run on the foreach loop in your gsp*/
def listParentNode = {
def parentId = params.id
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.parents(name: "Parents"){
Parent.findAllById(parentId).each {
Parent parentt = it
Parent( id:parentt.id,name:parentt.name) {
Children(name:'Children'){
parentt.children.each {
Child childd = it
child(name:childd.name,id:childd.id)
}
}
}
}
}
["data":writer.toString()]
//or render "data" as XML // depending on what the richui tag is expecting.
}
the other peice is in your gsp, leave the gsp file intact just change this part:
<td><richui:treeView xml="${createLink(controller:'somecontroller',action:'listParentNode', id: parentInstance.id )}" /></td>
somecontroller is the name of your controller where these actions are.

Related

Blazor update list in child component when parent event is fired

I try to update a list in my childcomponent when an event is triggered in the parent component. The code looks like this:
Parent:
#if (workflows == null)
{
<Loader />
}
else
{
#foreach (var item in workflows)
{
<fieldset>
<legend>
#item.Descr
</legend>
<table class="table table-slim">
<thead>
<tr>
<th>Beskrivning</th>
<th>Plats</th>
<th></th>
</tr>
</thead>
<tbody>
<WoTemplateRow Id="#item.WorkFlowItemId" #ref="woTemplateRow" />
</tbody>
</table>
<table class="table table-slim">
<tbody>
<tr>
<td>
<input type="text" class="form-control form-control--slim" placeholder="+ Skapa ny arbetsorder" #bind-value="#Descr" #onblur="(() => SaveNewRow(item.WorkFlowItemId))" />
</td>
</tr>
</tbody>
</table>
Parent code behind:
protected async Task SaveNewRow(int id)
{
newTemplate.Descr = Descr;
newTemplate.WorkFlowId = id;
await _repoTemplate.Create(EndPoints.TvWorkOrderEndpoint + $"CreateTemplate", newTemplate);
await OnNewRow.InvokeAsync();
Descr = "";
newTemplate = new();
await woTemplateRow.GetTemplates(); // THis is calling the child components function
}
ChildComponent code behind:
protected async override Task OnInitializedAsync()
{
OrgId = await _localstorage.GetItemAsync<int>("activeOrgId");
await GetTemplates();
locations = await _repoLocation.Get(EndPoints.TvWorkOrderEndpoint + $"GetLocations?orgId={OrgId}");
}
public async Task GetTemplates()
{
templates = await _repoTemplate.Get(EndPoints.TvWorkOrderEndpoint + $"GetTemplateByWorkFlowId?workFlowId={Id}");
}
The GetTemplates() function is called and I can see that the new item is added in dubug mode, but the new list item is not rendered until after I refresh the whole page. What have I missed?

Transfer value from parent to child onclick in Blazor

Say that I have several lists in a razor component with the name ListA that have a table of rows like this:
List 1, FirstValue Edit
List 2, Antoher Value Edit
List 3, A third value Edit
I then have another component nested within ListA that is called ListALayout.razor.
<div class="WidgetHead">
#if (model == null)
{
}
else
{
<div class="item">
<i class="fa fa-edit cursor" #onclick="(e => OpenPopup(popup, model.PageWidgetId))"></i>
<i class="fa fa-trash cursor"></i>
</div>
<div id="item2">
<div class="header">
#model.Widget
</div>
</div>
}
<ListALayout Id="Id" OnWidgetChange="HandleWidgetChange" #ref="layout" />
I now want to edit List2 and change the value. I want to do that by using a modal that's residing insige my ListALayout component so I can change it's values and save it back to the database.
How do I transfrer the id (or model object) from my parent component to the Child component when I click the Edit button so that I know that that is the row I want to edit?
You may use a Paramter, so you can have in your Component (ListALayout.razor) defined a Parameter
#code {
[Parameter]
public MyModelObject Model { get; set; }
}
Then you can use the Parameter to set the object for this component instance:
<ListALayout Model="#CurrentModelObject" />

Custom Blazor Component not reflecting binding properly

I have a big DxFormLayout with many DxFormLayoutGroups and each DxFormLayoutGroup has many DxFormlauoutItems. I'm wondering if it is possible to sompress the razor code by componentizing a few DxFormlauoutItems. Here is my code:
Page:
<EditForm Model="#_model" Context="editFormContext" OnValidSubmit="#HandleValidSubmit">
<DataAnnotationsValidator />
<DxFormLayout CssClass="dxFormLayoutHeaderStyle">
<DxFormLayoutGroup Caption="Options" ColSpanMd="12">
<DxFormLayoutItem Caption="" ColSpanMd="12">
#*The below is repeated multiple times*#
<Template>
<DxStackLayout ItemSpacing="10px">
<Items>
<DxStackLayoutItem Length="95%">
<Template>
<DxTextBox ReadOnly="true" #bind-Text="#_model.TooltipTextForNegotiationsDoneBySupplyManagement"
title="#_model.TooltipTextForNegotiationsDoneBySupplyManagement" SizeMode="SizeMode.Medium"/>
</Template>
</DxStackLayoutItem>
<DxStackLayoutItem Length="5%">
<Template>
<div class="stacklayout-item">
<DxCheckBox CheckType="CheckType.Switch" style="width: 100%" #bind-Checked="#_model.IsNegotiationsDoneBySupplyManagement"
Alignment="CheckBoxContentAlignment.Center" title="#_model.TooltipTextForNegotiationsDoneBySupplyManagement"/>
</div>
</Template>
</DxStackLayoutItem>
</Items>
</DxStackLayout>
</Template >
#*The above is repeated multiple times*#
</DxFormLayoutItem >
</DxFormLayoutGroup>
</DxFormLayout>
</EditForm>
#*The below become a component with parameters and bindings*#
<EditForm Model="#_model" Context="editFormContext" OnValidSubmit="#HandleValidSubmit">
<DataAnnotationsValidator />
<DxFormLayout CssClass="dxFormLayoutHeaderStyle">
<DxFormLayoutItem Caption="" ColSpanMd="12">
<Template>
<BudgetReleaseRequestDecisionPoint DecisionText="#_model.TooltipTextForNegotiationsDoneBySupplyManagement"
DecisionResult="#_model.IsNegotiationsDoneBySupplyManagement" />
</Template >
</DxFormLayoutItem >
</DxFormLayout>
</EditForm>
Component:
<style>
.stacklayout-item {
text-align: center;
height: 100%;
padding-top: 6px;
}
</style>
<DxStackLayout ItemSpacing="10px">
<Items>
<DxStackLayoutItem Length="95%">
<Template>
<DxTextBox ReadOnly="true" #bind-Text="#DecisionText" title="#DecisionText" SizeMode="SizeMode.Medium"/>
</Template>
</DxStackLayoutItem>
<DxStackLayoutItem Length="5%">
<Template>
<div class="stacklayout-item">
<DxCheckBox CheckType="CheckType.Switch" style="width: 100%" #bind-Checked="#DecisionResult"
Alignment="CheckBoxContentAlignment.Center" title="#DecisionResult"/>
</div>
</Template>
</DxStackLayoutItem>
</Items>
</DxStackLayout>
#code {
[Parameter]
public string DecisionText
{
get => _decisionText;
set
{
if (_decisionText == value) return;
_decisionText = value;
DecisionTextChanged.InvokeAsync(value);
}
}
[Parameter]
public bool DecisionResult
{
get => _decisionResult;
set
{
if (_decisionResult == value) return;
_decisionResult = value;
DecisionResultChanged.InvokeAsync(value);
}
}
[Parameter]
public EventCallback<string> DecisionTextChanged { get; set; }
[Parameter]
public EventCallback<bool> DecisionResultChanged { get; set; }
private string _decisionText;
private bool _decisionResult;
}
Issue:
I made it a razor component but I'm having issue as the model's properties are not getting updated on the main page. I can confirm this by one property: On the page, there is a SpinEdit that get enabled once model.IsNegotiationsDoneBySupplyManagement is set to true. That is not happening anymore once I went to component-mode:
<DxSpinEdit Id="amountSavedAfterNegotiations" #bind-Value="#_model.SavingsAfterNegotiations" Enabled="#_model.IsNegotiationsDoneBySupplyManagement" title="Savings (AED) after negotiations?" />
When I had the original code (without component/top-most code I pasted), togeling this checkbox would toggle the Enabled state of the SpinEdit. After I transferred to component, the Enabled state is not longer sensing changes to the model's property leading me to believe the model's properties on the page are not getting updated.
What is wrong with the way I wired the component?
The missing magic was on the Page where I was calling the components. This is what I was doing:
<BudgetReleaseRequestDecisionPoint DecisionText="#_model.TooltipTextForNegotiationsDoneBySupplyManagement" DecisionResult="#_model.IsNegotiationsDoneBySupplyManagement" />
This is the correct syntax:
<BudgetReleaseRequestDecisionPoint DecisionText="#_model.TooltipTextForNegotiationsDoneBySupplyManagement" #bind-DecisionResult="#_model.IsNegotiationsDoneBySupplyManagement" />
I had to change the DecisionResult to #bind-DecisionResult. Now the Page's model is reflecting the changes that occur to its properties with in component.

How to get a table row click event to work using Aurelia that then navigates to another page

I want to create a Master/Detail page with table being the master that you click on a row and then it navigates to a detail page
Take the Aurelia ContactManager example and replace the list with a table
List example:
<li repeat.for="contact of contacts" class="list-group-item ${contact.id === $parent.selectedId ? 'active' : ''}">
<a route-href="route: contacts; params.bind: {id:contact.id}" click.delegate="$parent.select(contact)">
<h4 class="list-group-item-heading">${contact.firstName} ${contact.lastName}</h4>
<p class="list-group-item-text">${contact.email}</p>
</a>
</li>
Table example:
<table class="table" if.bind="contacts" id="myTable">
<thead>
<tr>
<th>IDs</th>
<th>Name</th>
<th></th>
</tr>
</thead>
<tbody>
<tr repeat.for="contact of contacts" class="clickable-row ${contact.id === $parent.selectedId ? 'active' : ''}">
<a route-href="route: contacts; params.bind: {id:contact.id}" click.delegate="$parent.select(contact)">
<td>${contact.id}</td>
<td>${contact.name}</td>
</tr>
</tbody>
</table>
I know how to get the row onlick to work using jquery without Aurelia as in
$(".class='clickable-row").click(function() {
window.location = $(this).data("href");
});
but I do not know how to use aurelia navigation with the row click.
The solution does not necessarily need to use jquery onlcick just whatever is appropriate for the Master/Detail scenario with Aurelia
If you wanted to capture click on <tr> specifically
<tr repeat.for="contact of contacts" click.delegate="onSelectContact($event, contact)">
<td style="cursor: pointer;">lalala</td>
</tr>
and in your view-model, something like..
import { autoinject } from 'aurelia-framework'
import { Router } from 'aurelia-router'
import { Contact } from '../la/la'
#autoinject
export class Contacts {
contacts: Array<Contact> = []
constructor(private router: Router) {
}
onSelectContact (event: UIEvent, contact: Contact) {
...... // do whatever
this.router.navigateToRoute('contact', {id: contact.id})
}
...
}
however, this requires your router config to contain a
{ route: 'contact/:id', name: 'contact', moduleId: PLATFORM.moduleName('path to module'), title: 'Contact' }

ASP.NET MVC 4 Html.BeginForm in Partial View , values after post not right

Main Page
-> Section 1 (has some dropdowns and a save button)
<div id="tab-section1">
#{Html.RenderPartial("_Section1", Model.Section1);}
</div>
<div id="tab-section2">
<div id="section2">
#{Html.RenderPartial("_Section2", Model.Section2);}
</div>
#{Html.RenderPartial("_SubSection2", Model.SubSection2);}
</div>
The section 1 contents are placed in a partial view with #Html.BeginForm in it.
and rendered on main view using #Html.RenderPartial
#using MyData
#model Section1ViewModel
#using(Html.BeginForm("EditSection1", "Project", FormMethod.Post, new { id = "section1-form", name = "section-form" }))
{
#Html.HiddenFor(model => model.ProjectID)
<table id="modules">
<tr>
<td class="bold" colspan="2">Modules
</td>
</tr>
<tr>
<td>
#Html.DropDownListFor(m => m.SubmittedModules, new MultiSelectList(Model.AvailableModules, "ModuleID", "ModuleName", Model.SelectedModules.Select(m => m.ModuleID)),
new { multiple = "multiple", #class = "multiselectb" })
</td>
<td>
<input type="button" id="btnAddModule" value=" + " />
</td>
</tr>
#foreach (Module b in #Model.SelectedModules)
{
<tr>
<td colspan="2">
#b.ModuleName
</td>
</tr>
}
</table>
}
When i click the save button in partial view, it should update its own contents as well as other partial view SubSection2 should be refreshed.
In the action method, i return the new values, and for the second partial view updation, I create an ajax submit function where i do the #secondpartialview.load
Action:
[HttpPost]
public ActionResult EditSection1(Section1ViewModel viewModel)
{
Section1Data section1Data = new Section1Data(_UnitOfWork);
// save changes
section1Data.SaveSection1(viewModel);
viewModel = section1Data.GetSection1ViewModel(viewModel.ProjectID);
return PartialView("_Section1", viewModel);
}
Ajax submit:
$("#section1-form").submit(function () {
$("#section1-saving").html("<img src='../../Images/ajax-loader.gif' />");
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
$("#section1-saving").html("Saved!");
$.ajaxSettings.cache = false;
// Refresh the sub section 2 on the Section 2 tab
$("#subSection2").load('../../Projects/subSection2/' + $("#ProjectID").val());
},
error: function (jqXHR, textStatus, errorThrown) {
$("#section1-saving").html("Error: " + textStatus + " " + errorThrown);
}
});
return false;
});
The issue is: the DEBUGGER shows me the updated values for selectedModules in action method, but NOT on the UI.
What am i missing?
I had this kind of issue when i have multiple Partial view in a single Parent View.What you should do is that,
In the Parent View Call Section1 Paritial View
like
<div id="tab-section1">
#{Html.RenderPartial("_Section1", Model.Section1);}
</div>
Now in the _Section1 Partial View call your _Section2 Partial View
<div id="section2">
#{Html.RenderPartial("_Section2", Model.Section2);}
</div>
Using this Approach of Partial View inside of a Partial View you will be able to get Value from your UI.This is applicable for multiple partial view inside a parent view.
Also i like call my partial view like
#Html.Partial("ViewName",Model.ModelName)