How to edit grails column? - mysql

I need some conceptual answers.
In my grail application, I need to edit a column from a list view. The problem is that the column item(for instance an author)is linked to another domain(employee)class. So in order to edit the 'author' I have to edit 'employee' (just to clarify all author are from employee class) in the table. Not sure how I can search/get an employee from the list of employee in the column to replace an author.
I know in general I can edit any page, but this look somewhat different.
I am relatively new to groovy-grails.

You can use HTML table to retrieve list as below code
<table>
<thead>
<tr>
<g:sortableColumn property="id" title="ID" />
<g:sortableColumn property="author" title="Author" params="${filterParams}"/>
</tr>
</thead>
<tbody>
<g:each in="${EmployeeList}" status="i" var="employee">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td><g:link action="show" controller="employee" id="${employee.id}">${fieldValue(bean: employee, field: "id")}</g:link></td>
<td>${fieldValue(bean: employee, field: "author")}</td>
</tr>
</g:each>
</tbody>
</table>
And for searching you may use DataTables

Related

How to use CSS grid with a dynamic number of columns and rows?

I'm trying to create a table in Angular with a dynamic number of columns and rows. I've found this easy to accomplish using the HTML table element by doing something like this:
<table class="html-table">
<tr class="headers">
<th>Name</th>
<th>Age</th>
<th>Sex</th>
<th *ngIf="columns == 4">Species</th>
</tr>
<tr>
<td>Ryan</td>
<td>30</td>
<td>M</td>
<td *ngIf="columns == 4">Human</td>
</tr>
</table>
In this example there might be some button that toggles the value of columns between 3 and 4.
Every explanation I have looked at online involves changing CSS variables, which seems like a somewhat hacky way to accomplish something that should be simple. Is there some way I can specify that something should be a new column in CSS grid rather than that having to specify the number of columns in grid-template-columns?
In Angular you can use ng-repeat to have a dynamic table
A typical example could be
<table ng-table="tableParams" class="table table-striped">
<tr ng-repeat="data in datas">
<td title="Title_Of_First_Variable">{{data.variable1}}</td>
<td title="Title_Of_Second_Variable">{{data.variable2}}</td>
<td title="Title_Of_Third_Variable">{{data.variable3}}</td>
...
</tr>
</table>
Of course with your controller you should pass your dynamic data into the correct $scope, in this case should be $scope.datas (usually an object)...maybe something like this, using NodeJS:
$http.post('route_of_your_method')
.success(function (result) {
$scope.datas = result;
})
.error(function (err) {
...
});
I explained fastly but i hope this is enough

Angular 2+ : Condition based on previous index date value ngIf NgFor

Trying to format a table using Angular where:
If the day of the month changes, then you insert a new row which just contains the date (but also displays the data for that index value immediately below). If the day of the week is the same as before continue inserting the rows.
1) Clearly my code for accessing previous value in index is wrong but I can't seem to find anything clearly which helps.
2) I realise that my current code would compare the full datetime value and not just the day of the month (or week) but I am unsure how to do this in this scenario.
3) when the day changes and I try and insert the date line, I cannot get an additional new row formatted correctly which includes the data for that index value. I have tried playing around with various and combinations.
Please could someone help correct this code or point me in the right direction
Thanks
<table class="table-striped">
<thead>
<tr>
<td>day</td>
<td>time</td>
<td>region</td>
<td>event</td>
<td>period</td>
</tr>
</thead>
<tbody>
<tr *ngFor="let eco of eco_r ; let i = index">
<template [ngIf]="eco.date != eco[i-1].date">
<td colspan="5">{{eco.datetime| date:'longDate' }}</td>
<tr>
<td>{{eco.datetime | date:'EE'}}</td>
<td>{{eco.datetime | date:'shortTime'}}</td>
<td>{{eco.region}}</td>
<td>{{eco.event}}</td>
<td>{{eco.period}}</td>
</tr>
</template>
<template [ngIf]="eco.date == eco[i-1].date">
<td>{{eco.datetime | date:'EE'}}</td>
<td>{{eco.datetime | date:'shortTime'}}</td>
<td>{{eco.region}}</td>
<td>{{eco.event}}</td>
<td>{{eco.period}}</td>
</template>
</tr>
</tbody>
</table>
------------UPDATE ---------------
Following #Iancovici comments I have revised the following
i) corrected to reference eco_r[i-1].date
ii) Changed sql source to provide eco.day_of_month and eco.week_of_year to make it easier to reference and check conditions
iii) updated code to only check previous value when i > 0
I am still unable to get it to display a new line with the date AND also include the data for that value of i on a separate row where it formats correctly. Utilising as in my revised code puts all 5 values into the first column of the next row and messes put the table format. How should I resolve this please?
Thanks
<template [ngIf]="i >0 && eco.day_of_month != eco_r[i-1].day_of_month">
<tr><td colspan="5">{{eco.datetime| date:'longDate' }}</td>
</tr>
<tr> <td>{{eco.datetime | date:'EE'}}</td>
<td>{{eco.datetime | date:'shortTime'}}</td>
<td> {{eco.region}} </td>
<td>{{eco.event}}</td>
<td>{{eco.period}}</td>
</tr>
</template>
Should probbly be *ngIf not [ngIf] in general. But I see in your case it’s ok because you’re using an ng template which means instead of directive *ngIf it’s not a bonded property [ngIf]
Also you're accesing the same instance, should access index of array instead so..
change from
*ngIf="eco.date == eco[i-1].date">
to
*ngIf="eco.date == eco_r[i-1].date">
Update: Two more notes
Make sure you create a table, with tag
Don't be afraid to use paranthesis if conditonal expressions become more complex, so you can distinguish the two conditions.
Try this without the filters, then integrate the filters in.
<table>
<div *ngFor="let eco of eco_r; let i = index">
<div *ngIf="(i > 0) && (eco.day_of_month != eco_r[i-1].day_of_month)">
<tr>
<td colspan="5">{{eco.datetime }}</td>
</tr>
<tr>
<td>{{eco.datetime }}</td>
<td>{{eco.datetime }}</td>
<td> {{eco.region}} </td>
<td>{{eco.event}}</td>
<td>{{eco.period}}</td>
</tr>
</div>
</div>
</table>

Angular UI-Bootstrap typeahead in table

Simple question really, but how can I setup the typeahead to work in a table that works off of a different table than my typeahead?
For Example, I have a foreign key in a table and I want to let the users select this key based on the respective NAME value in the foreign key's primary table.
Code Example:
<table class="table table-bordered table-hover table-striped rwd-table" id="page-wrap">
<thead>
<tr>
<th>Primary ID</th>
<th>Foreign Key (As Name)</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="p in PrimaryTable" id="display">
<td data-th="ID">{{p.PrimaryID}}</td>
<td>
<input id="ForeignKeyName"
type="text"
ng-model="p.ForeignKeyID"
uib-typeahead="f.ForeignKeyID as f.ForeignKeyName for f in ForeignKeyTable | filter:$viewValue"
class="form-control">
</td>
</tr>
</tbody>
With this example, I would want the users to see the "Foreign Key (As Name)" As the Name value instead of the ID value. The trick is that I also want the underlying value to be the ID and have it mapped to match the original value, as notified by the ng-model.
UPDATE: Another question I had that was in line with the previous one is how do I setup my ng-model to show the ForeignKeyTable.ForeignKeyName in place of the PrimaryTable.ForeignKeyID?
This would be similar ( I imagine) to how the uib-typeahead matches the ForeignKeyTable.ForeignKeyID and ForeignKeyTable.ForeignKeyName but with the two seperate tables?
What I would desire is to be able to put ng-model: PrimaryTable.ForeignKeyID as ForeignKeyTable.ForeignKeyName
First thing would be updating PrimaryKeyTable rows every time user selects value in typeahead. You'll have to catch selected item and manually assign its ForeignKeyId value to the row of PrimaryTable.
The way to do it is to add typeahead-on-select directive to your typeahead and bind it to the function that assigns the values for you.
It would look like this:
HTML
<tr ng-repeat="p in PrimaryTable" id="display">
<td data-th="ID">{{p.PrimaryID}}</td>
<td>
<input id="ForeignKeyName"
type="text"
ng-model="selectedItem" <!-- could be anything really for we will not use it here -->
uib-typeahead="f.ForeignKeyID as f.ForeignKeyName for f in ForeignKeyTable | filter:$viewValue"
typeahead-on-select="onSelect($item, $model, $label, p)"
class="form-control">
</td>
</tr>
Inside your controller
$scope.onSelect = function($item, $model, $label, primaryKeyTableRow) {
primaryKeyTableRow.ForeignKeyId = $item.ForeignKeyId;
}
Next step is to display name property value of ForeignKeyTable row that corresponds to ForeignKeyId from PrimaryKeyTable in each row. Since we have to filter ForeignKeyTable to find suitable item it would be a good idea to put that logic inside the controller. For there are multiple rows in which we want to display corresponding name, we'll have to filter the ForeignKeyTable for each row separately. This is where ng-controller for ng-repeat comes in handy. What we'll do is bind new controller for each table row generated by ng-repeat and put some logic inside that controller. In HTML it would look like this:
<tr ng-repeat="p in primaryKeyTable" ng-controller="itemController">
<!-- ... -->
</tr>
And we'll have to define new controller in JS file:
app.controller('itemController', function() {
// ...
});
Now we can have separate logic for each row in the table. So that's a place to filter ForeignKeyTable to find corresponding item and display it's name.
Since whole code is kind of big I've put it in the plunker:
http://plnkr.co/edit/xccgnpxoPHg6vhXWPwZn?p=preview
See what you can do with it.

Use XPath in nodeset repeater (XForms)

I have a question about XPath and the nodeset repeater (XForms).
As you can see in the following code snippet I want to change an attribute of a specific entry of a list and additionally an attribute in the following entry in the nodeset with a trigger.
The first <xf:action> works fine but the second does not. What I want here is to leave the current nodeset of the processinstance, go to the following one and change the attribute state here. How do I realize that with XPath?
<div>
<xf:model>
<xf:instance xmlns="" id="template">
<project id="">
<name/>
...
<processinstance>
<name>
<state>
</processinstance>
</project>
</xf:instance>
</xf:model>
....
<!-- Process repeat table -->
<div>
<table class="table table-hover">
<thead>
<th width="50%">Processname</th>
<th width="50%">State</th>
<th width="50%">Action</th>
</thead>
<tbody id="process-repeat" xf:repeat-nodeset="//project[index('project-repeat')]/processinstance">
<tr>
<td>
<xf:output ref="name"/>
</td>
<td>
<xf:output ref="state"/>
</td>
<td>
<xf:group ref=".[state eq 'in processing']">
<xf:trigger appearance="minimal">
<xf:label>finish process</xf:label>
<xf:action>
<xf:setvalue ref="state">finished</xf:setvalue>
</xf:action>
<!-- THE FOLLOWING DOES NOT WORK AS I WANT! -->
<xf:action>
<xf:setvalue ref="//project[index('project-repeat')]/processinstance[index(process-repeat)+1]">in process</xf:setvalue>
</xf:action>
</xf:trigger>
</xf:group>
</td>
</tr>
</tbody>
</table>
</div>
</div>
Best regards,
Felix
One thing is that you have a typo:
index(process-repeat)
vs.
index('process-repeat')
In addition, the index() function represents the currently selected, in the UI, repeat iteration. It does not represent the current iteration being evaluated in XPath.
The bottom line is that you cannot use index('process-repeat') to identify the current repeat iteration. It is a common misunderstanding of the index() function.
Some implementations have functions to identify the current repeat iteration. I assume you are using BetterFORM, and I don't know if it has such a function. With Orbeon Forms you could write:
//project[index('project-repeat')]/processinstance[xxf:repeat-position()]
Or better, if betterFORM supports variables, you could use that to avoid repeating yourself with:
<tbody id="process-repeat" xf:repeat-nodeset="//project[index('project-repeat')]/processinstance">
<xf:var name="current-process" value="."/>
<tr>
<td>
<xf:output ref="name"/>
</td>
<td>
<xf:output ref="state"/>
</td>
<td>
<xf:group ref=".[state eq 'in processing']">
<xf:trigger appearance="minimal">
<xf:label>finish process</xf:label>
<xf:action>
<xf:setvalue ref="state">finished</xf:setvalue>
</xf:action>
<xf:action>
<xf:setvalue ref="$current-process">in process</xf:setvalue>
</xf:action>
</xf:trigger>
</xf:group>
</td>
</tr>
</tbody>

Order by in Thymeleaf

I need show this foreach by order Asc, how can I do it?
<tr th:each="ment : ${mentor}" th:if="${ment.jobId == job.id}">
<td th:text="${ment.id}"></td>
<td th:text="${ment.name}"></td>
<td th:text="${ment.qtyMentee}"></td>
<td th:text="${ment.jobId}"></td>
</tr>
This could be achieved with sort utility methods for lists, described here.
/*
* Sort a copy of the given list. The members of the list must implement
* comparable or you must define a comparator.
*/
${#lists.sort(list)}
${#lists.sort(list, comparator)}
Example
<tr th:each="ment : ${#lists.sort(mentor)}">
I had StackOverflow also, in my case I forgot to implement Comparable:
Comparable<E>
The error was missleading, thymeleaf could recognize that compareable needs to be implemented.