I'm a complete newbie in grails and I need you guys' help.
I have my sql query in the domain class. I put [1] to see the result but ultimately I'd like to send an argument in that place to display the result according to the person's id number.
def dataSource
def someMethod() {
def sql = new Sql(dataSource)
def resultRows = sql.rows('select * from result where id = ?', [1])
}
And this is what I have in my gsp.
<g:each in="${personInstance.someMethod()}" status="i" var="results">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td>${results.column_1}</td>
<td>${results.column_2}</td>
<td>${results.column_3}</td>
</tr>
</g:each>
How do I send a parameter from view to domain class?
Please help.
Thank you in advance.
If you want to see how Grails 'would like' your controller and view code to look, try letting Grails generate the code for you. Even if you don't keep that code in your final project, it is still useful as an instructional tool.
arc$ grails create-app Tester1
arc$ cd Tester1
arc$ grails
grails> create-domain-class Person
-- add some attributes to your Person domain class, save the file
grails> generate-all tester1.Person
Now go look at the PersonController.groovy, and the various views. Basically, it's marshal your data in the controller, pass it to the views, views operate on what they're given.
Very basic example of passing arbitrary data to the gsp:
// show method for an Adventure
def show(Adventure adventure) {
// a String to pass to the gsp
def attribute = 'Bilbo'
// an Array to pass to the gsp
def attributeList = ['Dwalin','Balin','etc']
// create a map of values that are 'automagically' passed
// to the show.gsp
[adventure: adventure, hobbit: attribute, dwarves: attributeList]
}
The adventure, hobbit, and dwarves variables are all available in the gsp. The template code likes to use verbose naming, like adventureInstance, but as long as your gsp code uses the keynames in the map you define, you're good to go.
Related
How to create edit forms. For url edit?id=1121 I want to display pre-filled data
EditForm(twf.Form):
class child(twf.TableLayout):
name= twf.TextField(name="name",value=DBSession.query(student.name).filter(student.id == <id passed in url>).distinct().all())
#expose ('edit')
def edit(self, id)
return dict(page='edit', , form=EditForm(action='/save')
Template:
<div>${form.display()}</div>
There are a few ways to achieve this, but I'd say that the cleanest one is passing the values to the form from the controller action as showcased by http://turbogears.readthedocs.io/en/latest/turbogears/widgets_forms.html#displaying-forms
In the case of your specific example it should result in having a form that only declares the fields that need editing and a reference to the edited object id:
class EditForm(twf.Form):
class child(twf.TableLayout):
student_id = twf.HiddenField()
name = twf.TextField(name="name")
Then within the controller you can fetch the edited object and provide the values to the form:
#expose('edit')
def edit(self, id):
edited_student = DBSession.query(student).filter(student.id==id).first()
return dict(page='edit',
form=EditForm(action='/save',
value=dict(student_id=id,
name=edited_student.name))
Keep in mind that this is just a proof of concept, I haven't tested the code and it lacks proper validation/error handling. But it should pretty much give the idea that you just pass the student name to the form through the value parameter when displaying it.
I'm trying to show the results from a stored procedure on a view. I have a ASP.NET MVC application with the following code. I used EntityFramework to generate the models.
public class ProjectsController : Controller
{
private DatabaseEntities db = new DatabaseEntities();
// GET: Projects
public ActionResult Index()
{
var projects = db.Projects.Include(p => p.Headquarter);
return View(projects.ToList(), db.CALCULATEBUDGET());
}
}
I get the following errors on this part: db.CALCULATEBUDGET()
Argument 1: cannot convert from 'System.Collections.Generic.List<TestApplication.Models.Project>' to 'string' TestApplication C:\TestApplication\TestApplication\Controllers\ProjectsController.cs 21 Active
Argument 2: cannot convert from 'System.Data.Entity.Core.Objects.ObjectResult<TestApplication.Models.CALCULATEBUDGET_Result>' to 'string' TestApplication C:\TestApplication\TestApplication\Controllers\ProjectsController.cs 21 Active
My stored procedure:
CREATE PROCEDURE dbo.CALCULATEBUDGET
AS
SELECT MonthlyRent, Budget, 100 * H.MonthlyRent/P.Budget AS RentPercentage
FROM Headquarter H, Project P
WHERE H.HeadquarterId = P.Headquarter_HeadquarterId
I'm trying to calculate how much percent the rent is from the budget. And then I want to show the results in a view.
first of all, when you return a View you need to either pass the name or leave it empty and then it works out using the defaults. You can pass a model as well, but what you've done is to pass two data items. The first one needs to be a View name:
return View( "YourViewName", yourDataModel);
The main concept of MVC is this : here is a View and here is the data for a View in the form of a model.
Directly throwing objects from a database at a view is usually a bad idea, I would suggest you decouple your things a little bit.
Have a business layer where you get the data, you map into a model object which matches what the view needs to display. Think of that as a translation layer from what your data looks like and what your View needs to display. Rule of thumb, only send to a View whatever it needs to display and nothing more.
You can combine multiple multiple data items in one data model for the View if that's what you need, but you still pass just one object to your View.
I have a Javascript table pulling data into it from a Laravel Json response, I have the column 'name' I wish to turn into a link when it is in the table? Is there anyway to do it like this:
"SELECT CONCAT('<a href=computer/?id=',id,'>',name,'</a>') as name,
I would rather use eloquent rather than straight SQL.
I really wouldn't advise building up HTML as part of your SQL query. Say you want to use that JSON feed somewhere else that doesn't support HTML in the field or you want to append a class to link you've got to change your code.
However there is nothing to wrong with building the link and passing that through you could consider using the Appending Values To JSON functionality of eloquent model.
So you could do something like
class Product extends Model
{
/**
* The accessors to append to the model's array form.
*
* #var array
*/
protected $appends = ['link'];
public function getLinkAttribute()
{
return route('routeName', ['id' => $this->id]);
}
}
If you really must pass back an anchor tag then you could use the link_to_route method which is part of the laravelcollective/html package.
How to pass $id to search scenario? Maybe in model look like this, so I can call like in controller like:
$model = new job('search',$id);
I think that you are trying to do a search. Search is one thing, a "scenario" is something else.
Scenarios are used in validation rules in order to be able to validate the same model in multiple ways depending from where you're inserting/adding OR searching data.
There's also a scenario called 'search' that is used by the model's search() method, but I tell you why:
There are a couple of ways to search for something in your database using Yii, I will mention two:
1) By using ClassName::model()->findCommandHere
And there are a couple of them:
ClassName::model()->findByPk($id);
ClassName::model()->findAll("id=$id");
ClassName::model()->findByAttributes(array('id'=>$id));
And so on, more here: http://www.yiiframework.com/doc/guide/1.1/en/database.ar#reading-record
2) By using the model's search() method
This way of finding data is mostly used for easily creating search pages and in combination with data grids.
If you generate CRUD code with the GII code generation tool it will generate all the parts for you, but I will explain each part how it works.
This code is from the blog demo found in Yii files:
In controller it defines a $model using Post class and 'search' as scenario.
$model=new Post('search');
if(isset($_GET['Post'])) // <- checks if there are search params in the URL
$model->attributes=$_GET['Post']; // <- assigns all search params masively to the model (later you'll see why)
$this->render('admin',array(
'model'=>$model,
));
The 'search' scenario here tells Yii what validation rules to use when assigning search parameters directly from $_GET (URL).
You can see that the params are assigned massively to reduce code written but $model->attributes=$_GET['Post'] it is the same as doing:
$model->title=$_GET['Post']['title'];
$model->status=$_GET['Post']['status'];
In the Post model you can find the validation rules for the search scenario. Tells Yii that it is safe to assign title and status fields in order to later use them in the search.
public function rules()
{
return array(
// ... //
array('title, status', 'safe', 'on'=>'search'),
);
}
Then also in the Post model you can see the search() method that will actually be used to get the data:
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('title',$this->title,true);
$criteria->compare('status',$this->status);
return new CActiveDataProvider('Post', array(
'criteria'=>$criteria,
'sort'=>array(
'defaultOrder'=>'status, update_time DESC',
),
));
}
The search method creates a "criteria" and applies the desired way of filtering using the values you have previously assigned to this model. See the $this->title it comes from the $model->attributes=$_GET['Post'] you used in the controller.
The criteria can be used directly on the model, such as Post::model()->findAll($criteria), but in this case the search() method uses something different, a "data provider".
The data provider is a good thing because it provides you a lot of tools in one place, it returns you the data, but also the pagination, and the sorting, so you don't have to manually define more code for that purposes (CPagination, CSort).
Finally, in the view admin.php in this case it will display the results using a grid view:
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
array(
'name'=>'title',
'type'=>'raw',
'value'=>'CHtml::link(CHtml::encode($data->title), $data->url)'
),
array(
'name'=>'status',
'value'=>'Lookup::item("PostStatus",$data->status)',
'filter'=>Lookup::items('PostStatus'),
),
),
));
Now you can see that in the configuration of the grid it passes $model->search() method as the dataProvider that the grid should use.
Now the grid can access the rest of the dataProvider elements such as sort, pagination and display them on the page.
If you did not want to use the CGridView because it's a very basic table and you want to create your own html markup, you can also retrieve the dataProvider and its components one by one and place them in your HTML code and display data as you want:
$dataProvider=$model->search(); // get the dataprovider from search method
$models=$dataProvider->getData(); // actually get the data (rows) and assign them to a $models variable that you can put in a foreach loop
// show pagination somewhere
$this->widget('CLinkPager', array(
'pages' => $dataProvider->pagination,
));
// create sort links
echo $dataProvider->sort->link('title', 'Title');
So I hope it solves some of your doubts on how to use Yii for displaying/searching data.
I suggest you read the official manual: http://www.yiiframework.com/doc/guide/1.1/en/index
I also suggest to look at the API and so search there all the Yii components to see what methods and params they have: http://www.yiiframework.com/doc/api/
Also exploring the framework codebase manually is quite a good way to learn. If you don't know how CActiveDataProvider works, then find the CActiveDataProvider class file in the code and you'll see all the methods and properties that it uses, so do this for everything you don't understand how it works.
Also for beginners I recommend using a good IDE that auto-completes code and allows you to Ctrl+Click a class name and it will locate the original file where it was defined. I use NetBeans for PHP and after creating a project I add Yii framework files to the project's include paths that way NetBeans knows how to find the framework files for auto-complete and for ctrl+click.
Yes you can define scenario with parameter but that is included within the class constructor of the model
$model = new Job('search'); // creating a model with scenario search
If you wish to include more parameters, then you need to use createComponent -remember, all is a component
$model = Yii::createComponent(array('class'=>'Job','scenario'=>'search'));
I think this will simply do the job without needing any scenario
$model = new job;
$model->search($id);
But If I have failed to understand your problem then you can also try this
$model = new job('search');
$model->search($id);
Think of scenarios as a special variable that you can use in the model.
$userModel = new User("register");
$userModel->setId = 10;
which is the same
$userModel = new User();
$userModel->scenario = 10
$userModel->setId = 10;
And in your model
class Manufacturer extends CActiveRecord
{
// :
if ($this->scenario == 'register') ...
// :
}
I learned that is this how to access a model from other controller,
var book = Alloy.Models.instance('book');
And this is how to access a property of a model,
var name = book.get('name');
However in the console,the name logs [INFO] : { } , meaning this doesn't get its property value, and ofcourse the model has already a data saved on it. Thanks for your help!
You may have to fetch the collection first:
var books = Alloy.Collections.book;
books.fetch();
This will load all the models from the collection so you can use them.
although the above works, there are a few addtional points here.
the call is asynchronous in most cases so you should be getting the model in a callback which is not presented in the code above.
I dont know if fetching the collection everytime you want a model is the correct approach either? If the collection already exists you just need to get the model from the collection just using the id.
depending on the exact use case, you might just want to pass the model as a parameter from one controller to the next