We've just moved over from bootstrap to Vuetify, but i'm struggling with something.
We have some updates sent (over signalR) that update a list of jobs, i'd like to be able to target a job that has been changed and change the row color for that particular job for a few seconds so the operator can see its changed.
Has anyone any pointers on how we can do this on a Vuetify v-data-table
Thanks
I ran into the same problem. This solution is a bit crude and a bit too late, but may help someone else.
In this example I change the colour of the row permanently until the page reloads. The problem with a temporary highlight is that if the table is sorted there is no way to put the row in the visible part of the table - v-data-table will put it where it belongs in the sort, even if it's out of the view.
Collect the list of IDs on initial load.
Store the list inside data of the component.
Use a dynamic :class attribute to highlight rows if the ID is not in the list (added or edited rows)
Solution in detail
1. Use TR in the items template to add a conditional class.
<template slot="items" slot-scope="props">
<tr :class="newRecordClass(props.item.email, 'success')">
<td class="text-xs-center" >{{ props.item.email }}</td>
:class="newRecordClass(props.item.email, 'success')" will call custom method newRecordClass with the email as an ID of the row.
2. Add an additional array to store IDs in your data to store
data: {
hydrated: false,
originalEmails: [], <--- ID = email in my case
3. Populate the list of IDs on initial data load
update(data) {
data.hydrated = true; // data loaded flag
let dataCombined = Object.assign(this.data, data); // copy response data into the instance
if (dataCombined.originalEmails.length == 0 ) {
// collect all emails on the first load
dataCombined.originalEmails = dataCombined.listDeviceUsers.items.map( item => item.email)
}
return dataCombined;
}
Now the instance data.originalEmails has the list of IDs loaded initially. Any new additions won't be there.
4. Add a method to check if the ID is in the list
newRecordClass(email, cssClass) {
// Returns a class name for rows that were added after the initial load of the table
if (email == "" || this.data.originalEmails.length==0) return "" // initial loading of the table - no data yet
if (this.data.originalEmails.indexOf(email) < 0 ) return cssClass
}
:class="newRecordClass(..." binds class attribute on TR to newRecordClass method and is being called every time the table is updated. A better way of doing the check would be via a computed property (https://v2.vuejs.org/v2/guide/computed.html#Computed-Properties). Vue would only call it when the underlying data changed - a method is called every time regardless.
Removing the highlight
You can modify newRecordClass method to update the list of IDs with new IDs after a delay to change the colour to normal.
#bakersoft - Did you find a solution? I suspect there is an easier way to skin this cat.
This may seem a simple question, but for some reason I am vexed.
I have a form with 3 datasources - InventTable, InventSum, InventDim.
So, for example, my grid shows;
Item, Name, Site, Warehouse, Physical Stock
I have placed a display method on InventDim form DataSource, but I need access to the ItemId from either inventTrans or InventSum. (Obviously looking for the "current" itemId).
All I can access is the inventDim which is passed as a parameter _inventDim, as standard.
What is the best way to access the "current" itemId?
Okay, I found the answer, with great thanks to this reference by Joris de Gruyter;
http://daxmusings.blogspot.co.uk/2011/10/forum-advanced-display-method-querying.html
The key was to put the display method on the InventSum datasource.
You can then use _inventSum.joinChild() to retrieve the linked inventDim, here is Joris' example;
display Qty AvailPhysical(InventSum _inventSum)
{
InventDim joinDim, dimValues;
InventDimParm dimParm;
InventSum localSum;
//THE IMPORTANT LINE...
dimValues.data(_inventSum.joinChild());
dimParm.initFromInventDim(dimValues);
select sum(AvailPhysical) from localSum where localSum.ItemId == _inventSum.ItemId
#InventDimExistsJoin(localSum.InventDimId, joinDim, dimValues, dimParm);
return localSum.AvailPhysical;
}
I am sure this will help someone out in the future!
Is there any way to use a different column for the first column in the group? By default it uses the same as the "Group Title" (the one with the "expand" triangle).
E.g. I want to bind the "Group" row to departmentTitle and the first column of the items in the group should have employeeTitle.
Like this:
-> departmentTitle
-->employeeTitle
-->employeeTitle
-->employeeTitle
-->employeeTitle
By default they use the same column like this:
-> departmentTitle
-->departmentTitle
-->departmentTitle
-->departmentTitle
-->departmentTitle
How can I change them from using the same column? I can just set it to "title" and make a return self.employeeTitle method but then I have to make that KVO compliant and mess up my model with workaround stuff. Am I missing something? Thanks
i might be late to answer this question, but here's what i did (it's not the most ellegant way of doing it, i'm certain)
you could have a property called "title" and bind the column to it.
also, define a property "departmentTitle" and "employeeTitle" which you'd initialize depending on whether an object is group or child object.
then define the "title" property's getter to return either "departmentTitle" or "employeeTitle" depending on your needs. it would look something like this:
- (NSString) title {
if (isLeaf) {
return self.employeeTitle;
}
else {
return self.departmentTitle;
}
}
as i said, it's not an ellegant solution but it worked like a charm for me.
I'm using WatiN to do some web testing and have run into a problem with a select list.
I have to run through a few pages first, adding a 'Category' element that will populate said troublesome select list.
I have been able to easily select an element from the list using ByValue, but the problem here is that the values is more of an index element that is created on the fly with a seemingly random value when the 'Category' element is created. I have tried to use the text that is under the option list in the html but it cannot seem to find it.
At this point I'm willing to settle for any element in the list that isn't value "-1" as this is the "Please select an option item".
Any help at all would be appreciated,
Thanks in advance
Keith 8o8
If i understand correctly maybe this can help:
OptionCollection options = browser.SelectList("elementId").Options;
options[0].Select();
Here is a solution :
SelectList list = _browser.Frame(Find.ById(frameId)).SelectList(listId);
foreach (Option tempOption in list.Options)
{
string value = tempOption.Text;
if (!string.IsNullOrEmpty(value)) // Compare with visible option text
{
if (value.Equals(option))
{
list.Option(option).Select();
found = true;
My main question here is dealing with the pramas map when having a one-to-many relationship managed within one dynamic form, as well as best practices for dealing with one-to-many when editing/updating a domain object through the dynamic form. The inputs for my questions are as follows.
I have managed to hack away a form that allows me to create the domain objects shown below in one Dynamic form, since there is no point in having a separate form for creating phone numbers and then assigning them to a contact, it makes sense to just create everything in one form in my application. I managed to implement something similar to what I have asked in my Previous Question (thanks for the people who helped out)
class Contact{
String firstName
String lastName
// ....
// some other properties
// ...
static hasMany = [phones:Phone]
static mapping = {
phones sort:"index", cascade: "all-delete-orphan"
}
}
class Phone{
int index
String number
String type
Contact contact
static belongsTo = [contact:Contact]
}
I basically managed to get the values from the 'params' map and parse them on my own and create the domain object and association manually. I.e. i did not use the same logic that is used in the default scaffolding, i.e.
Contact c = new Contact(params)
etc...., i just looped through all the params and hand crafted my domain objects and saved them and everything works out fine.
My controller has code blocks that look like this (this is stripped down, just to show a point)
//create the contact by handpicking params values
def cntct = new Contact()
cntct.firstName = params.firstName
cntct.lastName = params.lastName
//etc...
//get array of values for number,type
def numbers = params['phone.number']
def types = params['phone.type']
//loop through one of the arrays and create the phones
numbers.eachWithIndex(){ num, i ->
//create the phone domain object from
def phone = new Phone()
phone.number = num
phone.type = types[i]
phone.index = i
cntct.addToPhones(phone)
}
//save
My questions are as follows:
What is the best practice of handeling such a situation, would using Command objects work in this case, if yes where can i found more info about this, all the examples I have found during my search deal with one-to-one relationships, I couldn't find an example for one-to-many?
What is the best way to deal with the relatiohsips of the phones in this case, in terms of add/removing phones when editing the contact object. I mean the creation logic is simple since I have to always create new phones on save, but when dealing with updating a contact, the user might have removed a phone and/or editing an exiting one and/or added some new phones. Right now what I do is just delete all the phones a contact has and re-create them according to what was posted by the form, but I feel that's not the best way to do it, I also don't think looping over the existing ones and comparing with the posted values and doing a manual diff is the best way to do it either, is there a best practice on how to deal with this?
Thanks, hopefully the questions are clear.
[edit] Just for more information, phone information can be added and deleted dynamically using javascript (jquery) within the form [/edit]
disclaimer: i do not know if the following approach works when using grails. Let me know later.
See better way for dynamic forms. The author says:
To add LineItems I have some js that calculates the new index and adds that to the DOM. When deleting a LineItem i have to renumber all the indexes and it is what i would like to avoid
So what i do
I have a variable which stores the next index
var nextIndex = 0;
When the page is loaded, i perform a JavaScript function which calculates how many child The collection has and configure nextIndex variable. You can use JQuery or YUI, feel free.
Adding a child statically
I create a variable which store the template (Notice {index})
var child = "<div>"
+= "<div>"
+= "<label>Name</label>"
+= "<input type="text" name=\"childList[{index}].name\"/>"
+= "</div>"
+= "</div>"
When the user click on the Add child button, i replace {index} - by using regex - by the value stored in the nextIndex variable and increment by one. Then i add to the DOM
See also Add and Remove HTML elements dynamically with Javascript
Adding a child dinamically
Here you can see The Paolo Bergantino solution
By removing
But i think it is the issue grow up when deleting. No matter how many child you remove, does not touch on the nextIndex variable. See here
/**
* var nextIndex = 3;
*/
<input type="text" name="childList[0].name"/>
<input type="text" name="childList[1].name"/> // It will be removed
<input type="text" name="childList[2].name"/>
Suppose i remove childList1 What i do ??? Should i renumber all the indexes ???
On the server side i use AutoPopulatingList. Because childList1 has been removed, AutoPopulatingList handles it as null. So on the initialization i do
List<Child> childList = new AutoPopulatingList(new ElementFactory() {
public Object createElement(int index) throws ElementInstantiationException {
/**
* remove any null value added
*/
childList.removeAll(Collections.singletonList(null));
return new Child();
}
});
This way, my collection just contains two child (without any null value) and i do not need to renumber all the indexes on the client side
About adding/removing you can see this link where i show a scenario wich can gives you some insight.
See also Grails UI plugin
Thanks,
Your answer brought some insight for me to do a wider search and I actually found a great post that covers all the inputs in my question. This is just a reference for anyone reading this. I will write a blog entry on how I implemented my case soon, but this link should provide a good source of ino with a working exmaple.
http://www.2paths.com/2009/10/01/one-to-many-relationships-in-grails-forms/
Most of the time I use ajax to manage such problem.
So when the user clicks add new phone I get the template UI from the server for manageability purpose ( the UI just same GSP template that I use to edit, update the phone), so this way you are not mixing your UI with your js code, whenever you want to change the UI you have to deal only with our GSP code.
Then after getting the UI I add it to the page using jquery DOM manipulation. Then after filling the form when they hit add(save) the request is sent to the server via ajax and is persisted immediately.
When the user clicks edit phone the same UI template is loaded from the server filled with existing phone data, then clicking update will update the corresponding phone immediately via ajax, and same thing applies to delete operation.
But one day I got an additional scenario for the use case that says, "until I say save contact no phone shall be saved on the backend, also after adding phones to the contact on the ui if navigate away to another page and come back later to the contact page the phones I added before must be still there." ugh..
To do this I started using the Session, so the above operations I explained will act on the phone list object I stored on the session instead of the DB. This is simple perform all the operation on the phonesInSession but finally dont forget to do this(delete update):
phonesToBeDeleted = phonesInDB - phonesInSession
phonesToBeDeleted.each{
contact.removeFromPhones(it)
it.delete()
}
I know I dont have to put a lot of data in session but this is the only solution I got for my scenario.
If someone has got similar problem/solution please leave a comment.
First, in all your input fields names you add an #:
<input type="text" name="references[#].name"/>
Second, add call a function before submitting:
<g:form action="save" onsubmit="replaceAllWildCardsWithConsecutiveNumbers();">
Third, this is the code for the function that you call before submitting the form:
function replaceAllWildCardsWithConsecutiveNumbers(){
var inputs = $('form').find("[name*='#']");
var names = $.map(inputs, function(el) { return el.name });
var uniqueNames = unique(names);
for (index in uniqueNames) {
var uniqueName = uniqueNames[index];
replaceWildCardsWithConsecutiveNumbers("input", uniqueName);
replaceWildCardsWithConsecutiveNumbers("select", uniqueName);
}
}
function unique(array){
return array.filter(function(el, index, arr) {
return index === arr.indexOf(el);
});
}
function replaceWildCardsWithConsecutiveNumbers(inputName, name){
counter = 0;
$(inputName + "[name='" + name + "']").each(function (i, el) {
var curName = $(this).attr('name');
var newName = curName.replace("#", counter);
$(this).attr('name', newName);
counter += 1;
});
}
Basically, what the code for replaceAllWildCardsWithConsecutiveNumbers() does, is to create a list for all input (or select) elements whose name contains an #. Removes the duplicates. And then iterates over them replacing the # with a number.
This works great if you have a table and you are submitting the values to a command object's list when creating a domain class for the first time. If you are updating I guess you'll have to change the value of counter to something higher.
I hope this helps someone else since I was stuck on this issue for a while myself.