FromOutcome for `Switch Node` directing flow to `Method Call Node` don't wont to work - jsf-2

I have difined my flow as:
builder.id("", PublisherBean.PUBLISHER_FLOW_NAME);
builder.viewNode("list", "/pages/publishers.xhtml");
builder.viewNode("details", "/pages/publishers-details.xhtml");
builder.viewNode("deleted", "/pages/publishers-deleted.xhtml");
builder.viewNode("form", "/pages/publishers-form.xhtml");
builder.viewNode("exit", "/index.xhtml");
builder.methodCallNode("invoke-update")
.expression("#{publisherBean.update()}")
.defaultOutcome("details");
builder.methodCallNode("switch-fail")
.defaultOutcome("invoke-publishers")
.expression("#{publisherBean.switchFail()}");
builder.switchNode("proceed-action-request")
.defaultOutcome("switch-fail")
.switchCase()
.condition("#{publisherBean.actionType.ifEdit()}").fromOutcome("form");
builder.switchNode("go-for-it")
.defaultOutcome("switch-fail")
.switchCase()
.switchCase()
.condition("#{publisherBean.actionType.ifEdit()}").fromOutcome("invoke-update");
as you can see, there is two switch nodes. First directs to a View Node, second one is trying to direct to a Method Call Node.
First one works fine, however second is giving me a headache. Second one is giving me an error
Unable to find matching navigation case with from-view-id '/pages/publishers-form.xhtml' for action '#{publisherBean.proceed()}' with outcome 'proceed-form'.
proceed function is just
public String proceed() {
LOG.log(Level.OFF, "Form proceed in action type {0}", actionType);
return "go-for-it";
}
Logged info confirms, that publisherBean.actionType.ifEdit() returns true, however that fact is ignored. If i change outcome from invoke-update to form or any other View Node id, then it "works fine".
Is it i'm doing something wrong, or Method Call Node cant be used as an outcome to a Switch Node?

I run into this issue too. In my case the problem is in calling Method Call Node after another Method Call Node.
I invesigated it a bit and found a problem in: com.sun.faces.application.NavigationHandlerImpl.synthesizeCaseStruct method. This method is used to determine where to go from methodCallNode or switchCallNode and it only looks at viewNodes and returnNodes.
private CaseStruct synthesizeCaseStruct(FacesContext context, Flow flow, String fromAction, String outcome) {
CaseStruct result = null;
FlowNode node = flow.getNode(outcome);
if (null != node) {
if (node instanceof ViewNode) {
result = new CaseStruct();
result.viewId = ((ViewNode)node).getVdlDocumentId();
result.navCase = new MutableNavigationCase(fromAction,
fromAction, outcome, null, result.viewId,
flow.getDefiningDocumentId(), null, false, false);
} else if (node instanceof ReturnNode) {
String fromOutcome = ((ReturnNode)node).getFromOutcome(context);
FlowHandler flowHandler = context.getApplication().getFlowHandler();
try {
flowHandler.pushReturnMode(context);
result = getViewId(context, fromAction, fromOutcome, FlowHandler.NULL_FLOW);
// We are in a return node, but no result can be found from that
// node. Show the last displayed viewId from the preceding flow.
if (null == result) {
Flow precedingFlow = flowHandler.getCurrentFlow(context);
if (null != precedingFlow) {
String toViewId = flowHandler.getLastDisplayedViewId(context);
if (null != toViewId) {
result = new CaseStruct();
result.viewId = toViewId;
result.navCase = new MutableNavigationCase(context.getViewRoot().getViewId(),
fromAction,
outcome,
null,
toViewId,
FlowHandler.NULL_FLOW,
null,
false,
false);
}
}
} else {
result.newFlow = FlowImpl.SYNTHESIZED_RETURN_CASE_FLOW;
}
}
finally {
flowHandler.popReturnMode(context);
}
}
} else {
// See if there is an implicit match within this flow, using outcome
// to derive a view id within this flow.
String currentViewId = outcome;
// If the viewIdToTest needs an extension, take one from the currentViewId.
String currentExtension;
int idx = currentViewId.lastIndexOf('.');
if (idx != -1) {
currentExtension = currentViewId.substring(idx);
} else {
// PENDING, don't hard code XHTML here, look it up from configuration
currentExtension = ".xhtml";
}
String viewIdToTest = "/" + flow.getId() + "/" + outcome + currentExtension;
ViewHandler viewHandler = Util.getViewHandler(context);
viewIdToTest = viewHandler.deriveViewId(context, viewIdToTest);
if (null != viewIdToTest) {
result = new CaseStruct();
result.viewId = viewIdToTest;
result.navCase = new MutableNavigationCase(fromAction,
fromAction, outcome, null, result.viewId,
null, false, false);
}
}
return result;
}

Related

return List of Strings from Future / Stream

My Problem is very similar to the one mentioned here and here, but for some reason these are not working for me.
Basically, I want to do some simple I/O operations (on a mobile), returning of list of strings (folder path) that contain a certain file format (let's assume for the sake of argument that I want to find all mp3 files).
This is the code I have
Future<List<String>> getFolders() async {
List<String> _dirs = new List();
await SimplePermissions.requestPermission(Permission.ReadExternalStorage);
_dirs = await findAllFolders();
return _dirs;
}
Future<List<String>> findAllFolders() async {
Directory _root = Directory("/sdcard");
bool _notInList = true;
List<String> _dirs = new List();
_root.list(recursive: true, followLinks: false)
.listen((FileSystemEntity entity) {
if(entity.toString().contains("mp3")) {
if(_dirs.length==0) {
_dirs.add(entity.parent.path.toString());
} else {
_notInList = true;
for (var i = 0; i < _dirs.length; ++i) {
if(_dirs[i] == entity.parent.path.toString()) {
_notInList = false;
}
}
if(_notInList) {
_dirs.add(entity.parent.path.toString());
}
}
}
});
return _dirs;
}
where I want to use _dirs outside of getFolders().
I know that findAllFolders() returns _dirs immediately, before my listen() event has finished (and so its length is always 0, although the actual method works fine, i.e. if I put print statements where I have _dirs.add() I can see that the correct directories are added, _dirs contains what I want but I have no idea how to return the finished _dirs list). I tried to do something in a similar way to the above mentioned post, where a Completer is used (to which I am getting an error message "Bad State: Future already completed"). The respective code would be
Future<List<String>> findAllFolders() async {
Directory _root = Directory("/sdcard");
bool _notInList = true;
List<String> _dirs = new List();
Completer<List<String>> _completer = new Completer<List<String>>();
_root.list(recursive: true, followLinks: false)
.listen((FileSystemEntity entity) {
if(entity.toString().contains("mp3")) {
if(_dirs.length==0) {
_dirs.add(entity.parent.path.toString());
} else {
_notInList = true;
for (var i = 0; i < _dirs.length; ++i) {
if(_dirs[i] == entity.parent.path.toString()) {
_notInList = false;
}
}
if(_notInList) {
_dirs.add(entity.parent.path.toString());
}
}
}
_completer.complete(_dirs);
});
return _completer.future;
}
The getFolders() function remains the same in this case. Could anyone point out where my logic is going wrong?
You're setting a listener, then immediately returning before any results are received - that's why your return is always empty. The body of findAllFolders() needs to wait for a response before returning. Try the below to replace _root.list().listen():
List<FileSystemEntity> files = await _root.list(recursive: true, followLinks: false).toList();
for (FileSystemEntity entity in files) {
// Do your filename logic and populate _dirs

EF4 update navigation property An entity object cannot be referenced by multiple instances of IEntityChangeTracker

I am trying to implement a let's say "change my account email address" fonctionality.
I want to keep backup of all user emails in (R_EmailAddressHistory table).
Here are some of my project's code.
public bool ChangeEmailAddress(string username, string newEmailAddress, string callbackUrl)
{
DateTime currentUtcTime = DateTime.UtcNow;
R_User currentUser = UserRepo.GetSingle(whereCondition: w=>w.Username == username);
currentUser.UpdateDate = currentUtcTime;
if (currentUser.HasPendingNewEmail)
{
R_EmailAddressHistory currentPendingRequest = EmailHistoRepo.GetSingle(whereCondition: w => w.StatusID == (int)Reno.Common.Enums.RecordStatus.Pending && w.R_User.GId == currentUser.GId);
currentPendingRequest.NewEmail = newEmailAddress;
currentPendingRequest.UpdateDate = currentUtcTime;
EmailHistoRepo.Update(currentPendingRequest);
}
else
{
currentUser.HasPendingNewEmail = true;
R_EmailAddressHistory newEmail = new R_EmailAddressHistory();
newEmail.UserId = currentUser.GId;
newEmail.R_User = currentUser;
newEmail.NewEmail = newEmailAddress;
newEmail.InsertDate = currentUtcTime;
newEmail.StatusID = (int) Reno.Common.Enums.RecordStatus.Pending;
currentUser.R_EmailAddressHistory.Add(newEmail);
}
IdentityResult idtResult = UserRepo.Update(currentUser);
if(idtResult == IdentityResult.Succeeded)
{
//Send notification to current email address for validation before proceeding change email process
bool sendResult = Communication.EmailService.SendChangeEmailValidation(username,currentUser.Email, newEmailAddress, callbackUrl);
return sendResult;
}
else
{
return false;
}
}
The previous method is use to change an email address. Each of my tables (R_User and EmailAddressHistory ) has Repository (UserRepo and EmailHistoRepo). The implement the same IRepositoryBase class, here is the Update methode
public IdentityResult Update(T entity)
{
try
{
if (_currentContext.DbContext.Entry(entity).State == EntityState.Detached)
{
_currentContext.DbContext.Set<T>().Attach(entity);
}
_currentContext.DbContext.Entry(entity).State = EntityState.Modified;
return IdentityResult.Succeeded;
}
catch
{
return IdentityResult.Failed;
}
}
When a user has already a non validate new email address, when he request to change his current email address, I show him the pending new email address and he can change it, in this case I whant to update my historical table instead of creating a new one, cause only one pending new email address is allow. In such a case, my code failed in the line EmailHistoRepo.Update(currentPendingRequest) throwing the error : An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
Can anyone help me?
Thanks
EDIT
I am using MVC(4) with a unitOfWork. My UOW is initialized in a the Controller the first time the DB is queried and the Commit is done in the global.asax file in Appalication_EndRequest (see below).
protected void Application_EndRequest(Object sender, EventArgs e)
{
CommitChanges();
}
private void CommitChanges()
{
Reno.BLL.Services.Singleton.UnitOfWork unitOfWork = Reno.BLL.Services.Singleton.UnitOfWork.GetCurrentInstance(false);
if (unitOfWork != null)
{
unitOfWork.Commit();
unitOfWork.Dispose();
}
}
Your currentUser is modified before updating the emailaddress. Save the changes to currentUser first.
Something like this:
R_User currentUser = UserRepo.GetSingle(whereCondition: w=>w.Username == username);
currentUser.UpdateDate = currentUtcTime;
bool pendingNewEmail = currentUser.HasPendingNewEmail;
UserRepo.Update(currentUser);
if (pendingNewEmail)
{
R_EmailAddressHistory currentPendingRequest = EmailHistoRepo.GetSingle(whereCondition: w => w.StatusID == (int)Reno.Common.Enums.RecordStatus.Pending && w.R_User.GId == currentUser.GId);
currentPendingRequest.NewEmail = newEmailAddress;
currentPendingRequest.UpdateDate = currentUtcTime;
EmailHistoRepo.Update(currentPendingRequest);
}
else
I finally found the answer. The problem was that when I first get the user in line
R_User currentUser = UserRepo.GetSingle(whereCondition: w=>w.Username == username);
The currentUser variable hold a refrence of all of its R_EmailAddressHistory.
And then after, I queried the DB (2nd time) to get the pending email change request (or type R_EmailAddressHistory) to modify its new email and its update date, in line
R_EmailAddressHistory currentPendingRequest = EmailHistoRepo.GetSingle(whereCondition: w => w.StatusID == (int)Reno.Common.Enums.RecordStatus.Pending && w.R_User.GId == currentUser.GId);
currentPendingRequest.NewEmail = newEmailAddress;
currentPendingRequest.UpdateDate = currentUtcTime;
But te last code updates only currentPendingRequest while another reference of the same object which is in currentUser.R_EmailAddressHistory is not update and was already tracked by the context. Therefore, by doing an update on the new instance (EmailHistoRepo.Update(currentPendingRequest)), the code failed: the same object if referenced in 2 places.
So, the solution was (the only thing I modified):
R_User currentUser = UserRepo.GetSingle(whereCondition: w=>w.Username == username);
currentUser.UpdateDate = currentUtcTime;
if (currentUser.HasPendingNewEmail)
{
R_EmailAddressHistory currentPendingRequest = currentUser.R_EmailAddressHistory.Where(h => h.StatusID == (int)Reno.Common.Enums.RecordStatus.Pending).First(); // EmailHistoRepo.GetSingle(whereCondition: w => w.StatusID == (int)Reno.Common.Enums.RecordStatus.Pending && w.R_User.GId == currentUser.GId);
currentPendingRequest.NewEmail = newEmailAddress;
currentPendingRequest.UpdateDate = currentUtcTime;
}
I decided to modify the instance in currentUser variable.

Why am I getting this error in a basic Rails+Ember app?

I am trying to do a simple CRUD app using Ember + Rails and I'm getting the following error when trying to go to the /workouts route.
Error while loading route: TypeError {} ember.js?body=1:415
Uncaught TypeError: Object function () {
if (!wasApplied) {
Class.proto(); // prepare prototype...
}
o_defineProperty(this, GUID_KEY, undefinedDescriptor);
o_defineProperty(this, '_super', undefinedDescriptor);
var m = meta(this), proto = m.proto;
m.proto = this;
if (initMixins) {
// capture locally so we can clear the closed over variable
var mixins = initMixins;
initMixins = null;
this.reopen.apply(this, mixins);
}
if (initProperties) {
// capture locally so we can clear the closed over variable
var props = initProperties;
initProperties = null;
var concatenatedProperties = this.concatenatedProperties;
for (var i = 0, l = props.length; i < l; i++) {
var properties = props[i];
Ember.assert("Ember.Object.create no longer supports mixing in other definitions, use createWithMixins instead.", !(properties instanceof Ember.Mixin));
for (var keyName in properties) {
if (!properties.hasOwnProperty(keyName)) { continue; }
var value = properties[keyName],
IS_BINDING = Ember.IS_BINDING;
if (IS_BINDING.test(keyName)) {
var bindings = m.bindings;
if (!bindings) {
bindings = m.bindings = {};
} else if (!m.hasOwnProperty('bindings')) {
bindings = m.bindings = o_create(m.bindings);
}
bindings[keyName] = value;
}
var desc = m.descs[keyName];
Ember.assert("Ember.Object.create no longer supports defining computed properties.", !(value instanceof Ember.ComputedProperty));
Ember.assert("Ember.Object.create no longer supports defining methods that call _super.", !(typeof value === 'function' && value.toString().indexOf('._super') !== -1));
Ember.assert("`actions` must be provided at extend time, not at create time, when Ember.ActionHandler is used (i.e. views, controllers & routes).", !((keyName === 'actions') && Ember.ActionHandler.detect(this)));
if (concatenatedProperties && indexOf(concatenatedProperties, keyName) >= 0) {
var baseValue = this[keyName];
if (baseValue) {
if ('function' === typeof baseValue.concat) {
value = baseValue.concat(value);
} else {
value = Ember.makeArray(baseValue).concat(value);
}
} else {
value = Ember.makeArray(value);
}
}
if (desc) {
desc.set(this, keyName, value);
} else {
if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) {
this.setUnknownProperty(keyName, value);
} else if (MANDATORY_SETTER) {
Ember.defineProperty(this, keyName, null, value); // setup mandatory setter
} else {
this[keyName] = value;
}
}
}
}
}
finishPartial(this, m);
this.init.apply(this, arguments);
m.proto = proto;
finishChains(this);
sendEvent(this, "init");
} has no method 'find'
My code is located here: https://github.com/ecl1pse/ember-workouts
What am I doing wrong?
Edit: Upon further investigation I believe the culprit is
EmberWorkouts.WorkoutsRoute = Ember.Route.extend(
model: -> EmberWorkouts.Workout.find()
This doesn't actually return anything. How do I debug from there?
If I replace that with this
EmberWorkouts.WorkoutsRoute = Ember.Route.extend
model: -> [{title: 'hi'}, {title: 'damn'}]
The view actually renders content.
How do I get the model to collect from Rails properly?
Ember Data's interface has changed a little with the current release:
You can clear out the store.js file entirely. Ember Data will automatically set up a data store for you using the REST Adapter (unless you tell it otherwise).
Use model: -> #store.find('workout') instead.
I tested this with your app and it works.
If you haven't read through the Ember Data Guide in the last week or two (it's changed a lot), I would spend a few minutes on it.
The fix for this error (as of ember-data 1.0.0.beta.6) for me was to make sure that the JSON returned from the server included an "id" field for each model, BUT not to explicitly declare the id when setting up the Ember DS.Model.
jbuilder template:
json.scans do
json.array! #scans do |scan|
json.id scan.id # This prop has to be there
json.name scan.name
end
end
Ember model:
EmberApp.Scan = DS.Model.extend(
// Don't include the id prop here
name: DS.attr("string")
)

Entity Framework 5 - read a record then delete it in loop

I am having issues with my application. I have a db table for a print queue. When I read from that table in a loop, once I add that record to the view model, I then want to delete it from the database...this would be the most efficient way to do it, but EF barks:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
I've tried using multiple contexts... but that didn't seem to work either. I've seen articles like Rick Strahl's, but frankly it was above my level of understanding, and not exactly sure if it helps my issue here and seemed quite an in depth solution for something as simple as this.
Is there a simple way to accomplish what I am trying to achieve here?
Here is my code:
public List<InventoryContainerLabelViewModel> CreateLabelsViewModel(int intFacilityId)
{
var printqRep = new Repository<InventoryContainerPrintQueue>(new InventoryMgmtContext());
var printqRepDelete = new Repository<InventoryContainerPrintQueue>(new InventoryMgmtContext());
IQueryable<InventoryContainerPrintQueue> labels =
printqRep.SearchFor(x => x.FacilityId == intFacilityId);
List<InventoryContainerLabelViewModel> labelsViewModel = new List<InventoryContainerLabelViewModel>();
if (labels.Count() > 0)
{
//Get printq record
foreach (InventoryContainerPrintQueue label in labels)
{
IEnumerable<InventoryContainerDetail> icDtls =
label.InventoryContainerHeader.InventoryContainerDetails;
//Get print details
foreach (InventoryContainerDetail icDtl in icDtls)
{
labelsViewModel.Add(new InventoryContainerLabelViewModel()
{
...
populate view model here
}
);//Add label to view model
} //for each IC detail
//Delete the printq record
printqRepDelete.Delete(label); <======== Error Here
} //foreach label loop
}//label count > 0
return labelsViewModel.ToList();
}
In the end, I added a column to the printq table for status, then in the the loop updated it to processed, then called a separate method to delete it.
public List<InventoryContainerLabelViewModel> CreateLabelsViewModel(int intFacilityId)
{
InventoryMgmtContext dbContext = new InventoryMgmtContext();
var printqRep = new Repository<InventoryContainerPrintQueue>(dbContext);
IEnumerable<InventoryContainerPrintQueue> unprintedPrtqRecs =
printqRep.SearchFor(x => x.FacilityId == intFacilityId && x.Printed == false);
List<InventoryContainerLabelViewModel> labelsViewModel = new List<InventoryContainerLabelViewModel>();
if (unprintedPrtqRecs.Count() > 0)
{
//Get printq record
foreach (InventoryContainerPrintQueue unprintedPrtqRec in unprintedPrtqRecs)
{
IEnumerable<InventoryContainerDetail> icDtls =
unprintedPrtqRec.InventoryContainerHeader.InventoryContainerDetails;
//Get container details to print
foreach (InventoryContainerDetail icDtl in icDtls)
{
labelsViewModel.Add(new InventoryContainerLabelViewModel()
{
...
}
);//Get IC details and create view model
} //for each IC detail
unprintedPrtqRec.Printed = true;
printqRep.Update(unprintedPrtqRec, unprintedPrtqRec, false);
} //foreach label loop
//Commit updated to Printed status to db
dbContext.SaveChanges();
}//label count > 0
return labelsViewModel;
}
public ActionConfirmation<int> DeletePrintQRecs(int intFacilityId)
{
InventoryMgmtContext dbContext = new InventoryMgmtContext();
var printqRep = new Repository<InventoryContainerPrintQueue>(dbContext);
IEnumerable<InventoryContainerPrintQueue> printedPrtqRecs =
printqRep.SearchFor(x => x.FacilityId == intFacilityId && x.Printed == true);
foreach (InventoryContainerPrintQueue printedPrtqRec in printedPrtqRecs)
{
//Delete the printq record
printqRep.Delete(printedPrtqRec, false);
}
//Save Changes on all deletes
ActionConfirmation<int> result;
try
{
dbContext.SaveChanges();
result = ActionConfirmation<int>.CreateSuccessConfirmation(
"All Label Print Q records deleted successfully.",
1);
}
catch (Exception ex)
{
result = ActionConfirmation<int>.CreateFailureConfirmation(
string.Format("An error occured attempting to {0}. The error was: {2}.",
"delete Label Print Q records",
ex.Message),
1
);
}
return result;
}

displaying errors in grails without refreshing the page

I have a page with dynamic list boxes(selecting value from the first list populates the values in the second list box).
The validation errors for the list boxes are working fine, but while displaying the error messages the page is getting refreshed and the selected values are been set to initial status(need to select the values again in the list boxes)
The page is designed to add any number of list boxes using ajax calls, so adding and selecting the values again is going to be a rework.
Could you help me in displaying the validation errors and keeping the selected values as they are(previously I faced a similar situation which was resolved by replacing local variables of preprocess and postprocess with a global variable, this time no luck with that approach)
Any hints/help would be great
static constraints = {
deviceMapping(
validator: {val, obj ->
Properties dm = (Properties) val;
def deviceCheck = [:];
if (obj.customErrorMessage == null) {
for (def device : dm) {
if (device.key == null || "null".equalsIgnoreCase(device.key)) {
return ["notSelected"];
}
deviceCheck.put(device.key, "");
}
if (deviceCheck.size() != obj.properties["numberOfDevices"]) {
return ["multipleDevicesError"];
}
}
}
)
customErrorMessage (
validator: {
if ("sameDeviceMultipleTimes".equals(it)) {
return ['sameDeviceMultipleTimes']
}
}
)
}
public LinkedHashMap<String, Object> preProcess(sessionObject, params, request) {
Submission submission = (Submission) sessionObject;
def selectedFileName = sessionObject.fileName;
logger.debug("submission.deviceMapping :"+submission.deviceMapping)
try {
Customer customer = Customer.get(submission.customerId);
OperatingSystem operatingSystem = OperatingSystem.get(submission.operatingSystemId)
def ftpClientService = new FtpClientService();
def files = ftpClientService.listFilesInZip(customer.ftpUser, customer.ftpPassword, customer.ftpHost, customer.ftpToPackageDirectory, selectedFileName, operatingSystem, customer.ftpCustomerTempDirectory);
def terminalService = new TerminalService();
OperatingSystem os = OperatingSystem.get(submission.getOperatingSystemId());
def manufacturers = terminalService.getAllDeviceManufacturersForType(os.getType());
logger.debug("manufacturers after os type :"+manufacturers)
logger.debug("files in preprocess :"+files)
def devicesForFiles = [:]
files.each { file ->
def devicesForThisFile = [];
submission.deviceMapping.each { device ->
if (device.value == file.fileName) {
String manufacturer = terminalService.getManufacturerFromDevice("${device.key}");
def devicesForManufacturer = terminalService.getDevicesForManufacturerAndType(manufacturer, os.getType());
devicesForThisFile.push([device:device.key, manufacturer: manufacturer, devicesForManufacturer: devicesForManufacturer]);
}
}
devicesForFiles.put(file.fileName,devicesForThisFile);
}
logger.debug("devicesForFiles :"+devicesForFiles)
return [command: this, devicesForFiles: devicesForFiles, files: files, manufacturers: manufacturers];
} catch (Exception e) {
logger.warn("FTP threw exception");
logger.error("Exception", e);
this.errors.reject("mapGameToDeviceCommand.ftp.connectionTimeOut","A temporary FTP error occurred");
return [command: this];
}
}
public LinkedHashMap<String, Object> postProcess(sessionObject, params, request) {
Submission submission = (Submission) sessionObject;
Properties devices = params.devices;
Properties files = params.files;
mapping = devices.inject( [:] ) { map, dev ->
// Get the first part of the version (up to the first dot)
def v = dev.key.split( /\./ )[ 0 ]
map << [ (dev.value): files[ v ] ]
}
deviceMapping = new Properties();
params.files.eachWithIndex { file, i ->
def device = devices["${file.key}"];
if (deviceMapping.containsKey("${device}")) {
this.errors.reject("You cannot use the same device more than once");
return [];
//customErrorMessage = "sameDeviceMultipleTimes";
}
deviceMapping.put("${device}", "${file.value}");
}
if (params.devices != null) {
this.numberOfDevices = params.devices.size(); //Used for the custom validator later on
} else {
this.numberOfDevices = 0;
}
//logger.debug("device mapping :"+deviceMapping);
submission.deviceMapping = mapping;
return [command: this, deviceMapping: mapping, devicesForFiles: devicesForFiles ];
}
}
The problem is in your gsp page. Be sure that all field are initialised with a value
<g:text value="${objectInstance.fieldname}" ... />
Also the way it is selecting values is through id, so be sure to set it as well:
<g:text value="${objectInstance.fieldname}" id=${device.manufacturer.id} ... />

Resources