I noticed something when I was attempting this today:
<g:remoteField action="getReportsToResults" update="reportsToResultsDiv" paramName="search" name="reportsToResults" value="" />
I have this section of code where my remoteField is updating a div that contains a selection box. It works, but I want to limit the results passed to the div based on a domain instance attribute value (company ID). I have the instance variable (contactInstance.company).
When I try to add the params to that code, the value of search goes to '+this.value+', instead of the actual value of the text field. How does that happen and how do I pass both the field value and another parameter?
<g:remoteField action="getReportsToResults" update="reportsToResultsDiv" paramName="search" params="[company:contactInstance.company]" name="reportsToResults" value="" />
The error your are getting is because remoteFeild does not accept params as its parameters and when you use the keyword params it confuses the code (take a look at remotefield sourcecode). If you need to pass a parameter I would suggest to put them in Id and pass it to your controller.
for example :
<g:remoteField action="getReportsToResults" update="reportsToResultsDiv" paramName="search" params="[company:contactInstance.company]" name="reportsToResults" value="" id = "123"/>
RemoteField params are:
name (required) - the name of the field
value (optional) - The initial value of the field
paramName (optional) - The name of the parameter send to the server
action (optional) - the name of the action to use in the link, if not specified the default action will be linked
controller (optional) - the name of the controller to use in the link, if not specified the current controller will be linked
id (optional) - The id to use in the link
update (optional) - Either a map containing the elements to update for 'success' or 'failure' states, or a string with the element to update in which cause failure events would be ignored
before (optional) - The javascript function to call before the remote function call
after (optional) - The javascript function to call after the remote function call
asynchronous (optional) - Whether to do the call asynchronously or not (defaults to true)
method (optional) - The method to use the execute the call (defaults to "post")
source code from 1.3.7
def remoteField = { attrs, body ->
def paramName = attrs.paramName ? attrs.remove('paramName') : 'value'
def value = attrs.remove('value')
if (!value) value = ''
out << "<input type=\"text\" name=\"${attrs.remove('name')}\" value=\"${value}\" onkeyup=\""
if (attrs.params) {
if (attrs.params instanceof Map) {
attrs.params[paramName] = new JavascriptValue('this.value')
}
else {
attrs.params += "+'${paramName}='+this.value"
}
}
else {
attrs.params = "'${paramName}='+this.value"
}
out << remoteFunction(attrs)
attrs.remove('params')
out << "\""
attrs.remove('url')
attrs.each { k,v->
out << " $k=\"$v\""
}
out <<" />"
}
Related
I have a dropdown (g:select) in my view that displays a list from a domain class. I want to println whatever value that is in it whenever a save button is clicked. Below is the script in the view
<g:select params="[tablename: storehouseInstance?.tablename]" name="tablename" from="${Warehouse.list()}" optionKey="id" optionValue="${Warehouse.list()}" value="tablename"
noSelection="['':'Choose Table']"
onchange="${remoteFunction (
controller: 'warehouse',
action: 'updateSelect',
params: "'warehouse.id=' + this.value + storehouseInstance?.tablename" ,
param: "this.value",
update: [success:'fieldSelection'] //update: 'fieldselection'
)}"/>
And in my controller i have:
def save() {
println("params are "+ params)
println("Saving table name: " + params.tablename)
}
I am getting tablename to be '1' instead of the value that should be something like 'MYTESTVALUE'
Any help please.
Assuming the warehouse's name property is name, try this instead:
<g:select params="[tablename: storehouseInstance?.tablename]"
name="tablename"
from="${Warehouse.list()}"
optionKey="name" // I changed this line
optionValue="name" // I changed this line too
value="tablename"
noSelection="['':'Choose Table']"
onchange="${remoteFunction (
controller: 'warehouse',
action: 'updateSelect',
params: "'warehouse.id=' + this.value + storehouseInstance?.tablename" ,
param: "this.value",
update: [success:'fieldSelection']
)}"/>
In a g:select the parameter that is sent to the server is defined by optionKey and the value that is displayed in the dropdown is defined by optionValue
Aside
From an MVC purity point-of-view, you shouldn't be doing queries in GSPs, e.g. Warehouse.list(). Instead you should retrieve the data you need in a service/contoller and pass it via the model to the view (GSP).
I have the following
Rails HAML:
= select_tag "some-class",
options_for_select([['None', '']], ''),
{ class: 'some-other-class',
'ng-model' => 'someModel',
'ng-options' => 'option.name for option in someList',
'ng-change' => 'updateSelected()'}
Angular Controller:
scope.updateSelected = ->
#logic for updating model lives here. Model updates successfully by using some values defined within scope. Includes the following:
scope.someModel = "some_new_value"
Angular Directive:
SomeClassDirective= ->
restrict: 'C'
link: (scope, element, attrs) ->
monitorFormFields = (newValue, oldValue) ->
console.log "this is the inner function call"
#logic for setting the inner _destroy field lives here
scope.$watch 'someModel', monitorFormFields
However, when the Select List value is changed, 'this is the inner function call' never prints.(it does print when the directive first initializes, ie at page load). My question therefore is: Why isn't the $watch expression triggering, and how do I get it to trigger?
Thanks!
With this HTML:
<select class="some-class" ng-model="someModel"
ng-options="option.name for option in someList"></select>
Here is a directive that will watch for a change to someModel:
myApp.directive('someClass', function () {
return {
restrict: 'C',
link: function (scope, element, attrs) {
var monitorFormFields = function (newValue, oldValue) {
console.log("this is in the inner function call");
}
scope.$watch('someModel', monitorFormFields);
}
}
});
Controller:
$scope.someList = [{ name: 'name1' }, { name: 'name2' }];
Note that you don't need to call a controller method to update someModel -- Angular does that automatically for us because of the ng-model attribute. So, the directive only needs to $watch for a change to that $scope property.
Fiddle.
I would like to from the element fetch a sibling with [_destroy] in the name and set it to either "0" or "1" depending on the value of the select box.
A more Angular approach would be to have model properties control whether "0" or "1" is displayed. E.g., in your controller:
$scope.destroy1 = "0";
$scope.destroy2 = "0";
In your HTML:
<div>{{destroy1}}</div>
<div>{{destroy2}}</div>
In monitorFormFields() you can change the values of these scope properties, and the view will automatically update -- there is no need to "find" siblings or update .val()ues.
I'm using XMLSlurper. My code is below (but does not work). The problem is that it fails when it hits a node that does not have the attribute "id". How do I account for this?
//Parse XML
def page = new XmlSlurper(false,false).parseText(xml)
//Now save the value of the proper node to a property (this fails)
properties[ "finalValue" ] = page.find {
it.attributes().find { it.key.equalsIgnoreCase( 'id' ) }.value == "myNode"
};
I just need to account for nodes without "id" attribute so it doesn't fail. How do I do that?
You could alternatively use the GPath notation, and check if "#id" is empty first.
The following code snippet finds the last element (since the id attribute is "B" and the value is also "bizz", it prints out "bizz" and "B").
def xml = new XmlSlurper().parseText("<foo><bar>bizz</bar><bar id='A'>bazz</bar><bar id='B'>bizz</bar></foo>")
def x = xml.children().find{!it.#id.isEmpty() && it.text()=="bizz"}
println x
println x.#id
Apprently I can get it to work when I simply use depthFirst. So:
properties[ "finalValue" ] = page.depthFirst().find {
it.attributes().find { it.key.equalsIgnoreCase( 'id' ) }.value == "myNode"
};
I have a results view that displays a list of items.
In some cases, I want to display items where one field matches the query argument. In other cases, I want to display items where another field matches the query argument. And so on.
How can I provide arguments to my controller/view so that it knows what kind of results to get? I could write multiple controllers, but then I get the error that "Type 'MyType' already defines a member called 'MyMethod' with the same parameter type."
Ideally, I could find a way to do this without creating additional routes. Is this possible?
From what I understand from your question you want to do the following:
Reutilize a view, so that you don't have to make one for each query.
Use the same method name on a controller so that you don't have a different url for each query.
You could add an extra parameter to your method so that you can perform a different query depending on the value of the extra parameter:
public class QueryController
{
private enum QueryType
{
TypeA = 0,
TypeB = 1,
TypeC = 2
}
[HttpGet]
public void ShowResults(QueryType type, string criteria)
{
/*
* Code here to make the query using the field you want,
* depending on the "type" parameter e.g.
*
* switch (type)
* {
* case TypeA:
* model = db.Items.Where(x => x.FieldA == criteria);
* break;
* case TypeB:
* model = db.Items.Where(x => x.FieldB == criteria);
* break;
* }
*/
return View(model);
}
}
Another thing, don't worry about the routes, the default route {controller}/{method}/{id} doesn't demand that you have to specify the URLs in that strict way. This is a valid URL for the previous example:
http://www.example.com/App/Query/ShowResults?type=1&criteria=foo
The default MVC binder will use the parameter names in the URL to bind their values to the parameters of your method.
I hope I didn't misunderstood your question.
Good luck!
With MVC, query string values map to parameter values (and Routes are used to create custom mappings).
There are special exceptions though. If a parameter is a FormCollection (which is basically just a Dictionary<string>), then all un-mapped query string values will be passed in.
So, you can create a single Action that takes in all parameters:
// GET: MyController/ViewList?name=aaa&field1=foo&field2=bar
public ActionResult ViewList(string name, FormCollection otherFields) {
foreach (var field in otherFields) {
switch (field.Key.ToLower()) {
case "field1":
// Filter field1 based on field.Value
case "field2":
// Filter field2 based on field.Value
...
}
}
...
}
Similarly, you could also have no parameters, and just use this.Request.QueryString to inspect the query string values. However, I prefer the FormCollection method because it makes it clear that I expect other parameters.
I have a form with 2 input fields email and password(hidden) . I'm trying to generate a random value as below but failed to bind password(hidden) value after submit.
$password = substr(md5(rand(100000, 999999)), 0, 6);
$this->form->bind($request->setParameter('password',$password));
Form has the setNameformat with:
$this->widgetSchema->setNameFormat('user[%s]');
If a doctrine (or propel) form, I would do this by setting the values on the object before passing to the form constructor, and completely removing the widget from the form.
eg:
$o = new DoctrineOrPropelObject;
$o->setPassword($myrandomstring);
$f = new DoctrineOrPropelObjectForm($o);
Then display/save the form as usual - the password value will be passed right through the form process to the database when saved.
if you use this:
$this->widgetSchema->setNameFormat('user[%s]');
then your form input fields can be retrieved in single variable:
$request->getParameter('user');
and the value that you want to assign need to be set with something like:
$request->setParameter('user[password]', $password);
Reference can be found here.
Regards.
You can override the save method of your form and add $this->values[$field] = $value;
Something like this:
public function save($con = null)
{
$this->values['owner_id'] = $this->values['owners_ids'][2];`
return parent::save($con);
}