I got rid of the original UPDATE gsp Grails offers.
I put it in the first row of my list.gsp table and change all the values of the table to g:textfield so they can be edited without going to the save.gsp
But now I'm trying to make it work, and I can't.
I added a update button in the last column of the row, of every row.
When I change the values of the g:textfields and click the update button it tells me
Density #ID updated
but the values do not change.
I think I am doing something wrong with def update in the controller.
Here is the code:
def update = {
log.info "Entering Action ${actionUri}"
def densityInstance = Density.get(params.id)
if (densityInstance) {
if(params?.Rcommodity) {
println "${params.Rcommodity}"
}
if (params.version) {
def version = params.version.toLong()
if (densityInstance.version > version) {
densityInstance.errors.rejectValue("version", "default.optimistic.locking.failure", [message(code: 'density.label', default: 'Density')] as Object[], "Another user has updated this Density while you were editing")
render(view: "list", model: [densityInstance: densityInstance])
return
}
}
densityInstance.properties = params
if (!densityInstance.hasErrors() && densityInstance.save(flush: true)) {
flash.message = "${message(code: 'default.updated.message', args: [message(code: 'density.label', default: 'Density'), densityInstance.id])}"
redirect(action: "list", id: densityInstance.id)
}
else {
redirect(action: "list", id: densityInstance.id)
}
}
else {
flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'density.label', default: 'Density'), params.id])}"
redirect(action: "list")
}
}
The Rcommodity is the name of the textfields created, I put a println to see if the value was right, now I don't know how to make the value of the textfield be the one entered, it gives me the same value it had before but it gives me the message saying that it was updated.
The controller is DensityController and the domain is density
Any help would be greatly appreciated. Thanks :D
Looks from the flash message being printed as though the instance is being updated (though the "#ID" bit looks odd - have you replaced the actual id?).
It might be that
densityInstance.properties = params
is not actually be matching any instance properties, so none are actually being changed before the save. Are you sure you've named your gsp input fields to match the names of your Density class fields? Is Rcommodity a property of Density, for example?
Might help to add the form bit of your gsp page, as well as the Density domain class.
Related
I have four checkbox and I want to check automatically checkbox with id = 2 if checkbox with id = 4 is checked.
I did the following but did not get the output. Could someone help me with this.
{#each category in checkboxList}}
{{input id = category.CHECKBOX_ID type="checkbox" checked=category.IS_CHECKED}}
{{#if category.CHECKBOX_ID == 4 && category.IS_CHECKED == true}}
{{action 'CheckSize'}}
{{/if}}
The checkboxList is
[
{"IS_CHECKED":false,"CHECKBOX_ID":1},
{"IS_CHECKED":false,"CHECKBOX_ID":2},
{"IS_CHECKED":true,"CHECKBOX_ID":3},
{"IS_CHECKED":false,"CHECKBOX_ID":4}
]
You'll want to manage the state of the checkboxes separately.
Here is an example I did for another SO question that had a similar problem to solve:
https://ember-twiddle.com/468a737efbbf447966dd83ac734f62ad
The gist of it is
we use a single action in response to a click of any checkbox:
#action
toggleChecked(id) {
const newTree = check(this.options, id);
this.set('options', newTree);
}
In this example (taken from the ember-twiddle), all of the logic is extracted to a pure-function named check.
Check itself is pretty involved, but because the application logic is different between that example and the problem you've run in to, I'll just show the entry point function:
export function check(tree, id, transform = toggle) {
if (tree === undefined) return undefined;
if (Array.isArray(tree)) {
return tree.map(t => check(t, id, transform));
}
if (tree.id === id || id === 'all') {
return checkNode(tree, id, transform);
}
if (tree.children) {
return checkChildren(tree, id, transform);
}
return tree;
}
This is just an example of how you can immutably modify the representation of all checkboxes by using a pure function. Your logic may vary.
Hope this helps :)
In grails, I am trying to get a list of checked check boxes.
I have the list of check boxes, but my issues are two:
1) when I click on a single item in the list and click submit - I only get the value "on". If I click more than one check box item, I get something like this:
[Ljava.lang.String;#5a37f9f7
2). I do not get a list or the name of the item checked.
Here is my code for the check boxes in the gsp:
<g:form action="submitForm">
<ul class="columns3">
<g:each in="${name}" var="fileName" >
<g:checkBox value="${false}" name="${ 'fileName'}" /> ${fileName.replaceFirst(~/\.[^\.]+$/, '')}<br>
</g:each>
</ul>
<br>
<br>
<g:submitButton name="Submit"/>
</g:form>
and here is the controller code (groovy):
class Read_dirController {
def index() {
def list = []
def dir = new File("/home/ironmantis/Documents/business/test_files")
dir.eachFileRecurse (FileType.FILES) { file ->
list << file
}
list.each {
println it.name.replaceFirst(~/\.[^\.]+$/, '')
}
render(view: "index", model: [name:list.name])
params.list('fileName')
}
def displayForm() { }
def submitForm(String fileName) {
render fileName
//render(view: "tests_checked", fileName)
}
}
I tried to bind an id to the check boxes, but I keep getting an exception error.
Any help you can give I truly appreciate it; I am new to grails.
ironmantis7x
You can use the beautiful command object for this. For this ,first make a class RequestCO having the boolean fields.
class RequestCO {
boolean isChecked;
String name;
}
And
class RequestParentCO {
List<RequestCO> requestCOs = [].withLazyDefault { new RequestCO() }
}
Now you just simply bind all your request to RequestParentCO in your action:
def submitForm(RequestParentCO parentCO) {
println parentCO.requestCOs.findAll { it.isChecked }
}
This will give you all the checked checkboxes results.
GSP
<g:form action="process">
<ul class="columns3">
<g:each in="${["one", "two", "three"]}" var="fileName" status="i">
<g:hiddenField name="requestCOs[${i}].name" value="${fileName}"/>
<g:checkBox name="requestCOs[${i}].isChecked"/> ${fileName}<br>
</g:each>
</ul>
<g:submitButton name="Submit"/>
This way,
def submitForm() {
def values = request.getParameterValues("fileName")
//here values contains string array which are selected in checkbox
}
you can use request.getParameterValues("fileName") method, this will give selected checkbox in string array
I'm trying to do something which must be really simple to accomplish in Ember.
I want to show a button in my template based on the boolean state of a property:
{{#if canFavoriteTag}}
{{d-button action="favoriteTag" label="tagging.favorite" icon="star-o" class="admin-tag favorite-tag"}}
{{else}}
{{d-button action="unFavoriteTag" label="tagging.unfavorite" icon="star-o" class="admin-tag favorite-tag tag-unfavorite"}}
{{/if}}
I have created a property called canFavoriteTag with a function which I want to return true or false to the template based on whether the user can favorite the tag or not:
export default Ember.Controller.extend(BulkTopicSelection, {
canFavoriteTag: function() {
const self = this;
var ticker = this.get('tag.id');
console.log('checking can fav stock:' + ticker);
Discourse.ajax("/stock/get_users_favorite_stocks", {
type: "GET",
}).then(function(data) {
var favable = true;
for (var i = data.stock.length - 1; i >= 0; i--) {
var stock = jQuery.parseJSON(data.stock[i]);
if(ticker.toLowerCase() == stock.symbol.toLowerCase()) { console.log(ticker + ' is a favorite stock: ' + stock.symbol.toLowerCase()); favable = false; }
}
console.log(favable);
return favable;
});
}.property('canFavoriteTag') <-- unsure about this?
...
When the page loads, the wrong button shows (always the "false" one).. I see in the console that the favable variable gets set to false when the ajax call completes, but the button never changes. How do I get it to show the right button based on the function? Do I need to use a promise? If so, how?
I have test for the save action of a controller. It just executes the action with correct params, but the problem is on the redirectedUrl line: it is null.
Using the app, after saving the domain instance, I get the redirection to the show action and the show view is rendered correctly.
Any clues of what's the problem here?
The controller:
#Transactional(readOnly = true)
class FolderController {
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
...
#Transactional
def save(Folder folderInstance) {
if (folderInstance == null) {
notFound()
return
}
if (folderInstance.ehrId)
{
def ehr = ehr.Ehr.get(folderInstance.ehrId)
ehr.directory = folderInstance
ehr.save()
}
if (folderInstance.hasErrors()) {
respond folderInstance.errors, view:'create'
return
}
folderInstance.save flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'folder.label', default: 'Folder'), folderInstance.id])
redirect folderInstance
}
'*' { respond folderInstance, [status: CREATED] }
}
}
...
}
The test:
#TestFor(FolderController)
#Mock(Folder)
class FolderControllerSpec extends Specification {
...
void "Test the save action correctly persists an instance"() {
when:"The save action is executed with a valid instance"
response.reset()
populateValidParams(params)
def folder = new Folder(params)
controller.save(folder)
println folder.errors // no errors
then:"A redirect is issued to the show action"
response.redirectedUrl == '/folder/show/1'
controller.flash.message != null
Folder.count() == 1
}
...
}
The output:
junit.framework.AssertionFailedError: Condition not satisfied:
response.redirectedUrl == '/folder/show/1'
| | |
| null false
org.codehaus.groovy.grails.plugins.testing.GrailsMockHttpServletResponse#112b2f1
at directory.FolderControllerSpec.Test the save action correctly persists an instance(FolderControllerSpec.groovy:61)
Grails scaffold controllers are smarter controllers. They respect the request format and generate the response accordingly.
For example your save action -- it redirects to the show action if the request format is form otherwise it returns saved domain instance with status CREATED.
Following code is responsible for this
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'folder.label', default: 'Folder'), folderInstance.id])
redirect folderInstance
}
'*' { respond folderInstance, [status: CREATED] }
}
And in you test cases, your request is not of form type and hence redirectedUrl is null.
To make form request, add following code in you test case before making save call--
request.format = 'form'
Hope this helps.
I forgot to add the allowedMethods field.
The first problem was that the generated tests doesn't sets the right request method for the correspondent actions, so to call .save() this is needed: controller.request.method = "POST"
Then what #user1690588 suggested (request.format = 'form') did the trick to get the right redirectedUrl.
My final test looks like this:
void "Test the save action correctly persists an instance"() {
when:"The save action is executed with a valid instance"
response.reset()
populateValidParams(params)
def folder = new Folder(params)
controller.request.method = "POST"
request.format = 'form'
controller.save(folder)
then:"A redirect is issued to the show action"
response.redirectedUrl == '/folder/show/1'
controller.flash.message != null
Folder.count() == 1
}
In my application, I have an overall controller that manages state for a portion of the application, called SimpleSearch.
Within SimpleSearch, I have multiple SimpleSearchOptions, that display a list of choices to a user.
A user can select an option, and that selection is an action that is called from the view, that bubbles up to the SimpleSearchOptionController:
App.SimpleSearchOptionController = Ember.ObjectController.extend({
//....
select: function (option) {
option.queryName = this.get('queryName');
this.get('simpleSearch').setSelection(option);
this.set('selectedOption', option);
this.set('hasSelectedOption', true);
this.send('transitionToNextOption');
},
//....
This action calls this.get('simpleSearch').setSelection(option);, which registers the selection with the SimpleSearchController:
App.SimpleSearchController = Ember.ObjectController.extend({
//....
setSelection: function (option) {
this.set(option.queryName, option.value);
this.get('selectedOptions').set(option.queryName, option.value);
this.get('model').notifyPropertyChange('selectedOptions');
this.checkIfAllOptionsSelected();
},
//....
The important line in there is: this.set(option.queryName, option.value);.
After it registers the selection, it moves to the next option, and if there isn't one, it skips to the results of the search. That is called from this.send('transitionToNextOption');
App.SimpleSearchOptionController = Ember.ObjectController.extend({
//....
transitionToNextOption: function () {
var nextOptionId = parseInt(this.get("id")) + 1;
var numOfOptions = this.get('simpleSearch.numOfOptions');
if (nextOptionId < numOfOptions) {
this.transitionToRoute('simpleSearchOption', nextOptionId);
}
else {
this.transitionToRoute('simpleSearchResults');
}
},
//....
In setSelection() above, the line this.set(option.queryName, option.value); is setting a query parameter's value. This only works correctly, and the url gets updated accordingly for all options, when I'm not transitioning to a different route.
If I comment out the lines:
else {
this.transitionToRoute('simpleSearchResults');
}
Setting the property (this.set(option.queryName, option.value);) actually has the side effect of Ember updating the query parameter in the URL, which is my intent. If I include that line, and transition to a different route after setting that variable, the query parameter is not updated.
I was stepping through Ember's code, but I can't quite follow how it handles this. It continues into _doTransition(), and I've noticed that the transition to the route 'simpleSearchResults' always happens before the queryParams are passed through.
How do I get Ember to update the query parameter before it transitions to 'simpleSearchResults'?
Thank you for any and all help.
I solved my issue by wrapping the transition in an Ember.run.next() function:
transitionToNextOption: function () {
var nextOptionId = parseInt(this.get("id")) + 1;
var numOfOptions = this.get('simpleSearch.numOfOptions');
if (nextOptionId < numOfOptions) {
this.transitionToRoute('simpleSearchOption', nextOptionId);
}
else {
var self = this;
Ember.run.next(function() { self.transitionToRoute('simpleSearchResults'); });
}
},
I'm assuming, but have not verified, that Ember was queuing up the action to transition to 'simpleSearchResults', and handles the query parameters similarly. Perhaps the transition to a different route was somehow interrupting or overwriting the query parameter being written to the URL.