MVC consideration in Laravel - laravel

Is it right to use php code or blade code in view file using laravel?
for MVC consideration is it better to sepearate front end code like HTML with any server side code and keep them in corresponding controller file ?
for example using like this:
in view:
<table>
<Loop> <!-- instate of using #foreach -->
<tr>
<td>
<-UserId->
</td>
<td>
<-UserName->
</td>
</tr>
</Loop>
</table>
in controller:
$html = view('page');
$loop_section=my_own_func_to_get_loop_tag_content($html);
//edit loop_section var with php foreach and return resault to $modified_loop_section var
$html=str_replace($loop_section,$modified_loop_section,$html);
return $html;
Updated:
above code is just an example way that isn't seemed a good way.
but i look for better way to separate any php code (including if foreach etc) with html code in view file without using a custom tag and code?

Yes you should definitely use Blade code in your templates. So function my_own_func_to_get_loop_tag_content should be processed in template file, but it should only show data. All business logic (such as DB querying, sorting, calculations, ...) should be done in your controllers. View is only for displaying data, so there shouldn't be any logic.

Related

Thymeleaf: Form submit on click of table row

I have a table with orders and order ids. I would like to click on a row to view the order details in another page. My code:
<form id="orderDetalsForm" th:action="#{/restaurant/orderdetails}"
method="POST" th:object="${order}">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th scope="col">Order Id</th>
<th scope="col">Order Details</th>
<th scope="col">Date</th>
<th scope="col">Amount</th>
</tr>
</thead>
<tbody>
<tr id="orderRow" th:each="order : ${orders}"
style="cursor: pointer"
th:onclick="'getOrderItems(\''+${order.orderId}+ '\');'">
<td scope="row" th:text="${order.orderId}"></td>
<td th:text="${order.orderDetais}"></td>
<td th:text="${order.orderDate}"></td>
<td th:text="${order.amount}"></td>
</tr>
<tr>
<td colspan="3">Total</td>
<td th:text="${grandTotal}"></td>
</tr>
</tbody>
</table>
</form>
I tried an ajax form submit:
<script>
function getOrderItems(orderId) {
var url = "/restaurant/orderdetails";
$.ajax({
url : url,
type : "post",
data : {
"orderId" : orderId
},
success : function(data) {
console.log(data);
},
error : function() {
console.log("There was an error");
}
});
}
</script>
In my controller I have this:
#PostMapping(value="/restaurant/orderdetails")
public ModelAndView orderDetails(#RequestParam String orderId){
List<Product> orderDetails = userService.getOrderDetails(orderId);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("orderDetails", orderDetails);
modelAndView.setViewName("restaurant/orderdetails");
return modelAndView;
}
While the ajax works, the page is not getting redirected to my orderdetails page.
You can't use AJAX to redirect to a page. AJAX is for getting data from the server that is then processed/displayed using JavaScript. You however basically want clicking on the row to behave like clicking a link or (since you are using a POST mapping) submitting a form.
First off, using POST makes this a bit more complicated. You should consider using a GET mapping, not only because it makes this problem easier, but also because a POST mapping isn't really appropriate here. POST is used to send data to the server, which you are not doing.
Another thing you should consider it that using a (pure) JavaScript solution to link the table row hinders accessibility. For example, users that can't/don't use a mouse (such as disabled people or search engines) won't be able to see or even use such a link. To solve this it is a good idea to add a proper link to the row. Then that link can used by "clicking" on it with the JavaScript of the click handler.
<tr th:each="order : ${orders}" onclick="orderRowClick(this)">
<td scope="row"><a th:href="#{/restaurant/orderdetails(orderId=${order.orderId})}" th:text="${order.orderId}"></a></td>
<td th:text="${order.orderDetais}"></td>
<td th:text="${order.orderDate}"></td>
<td th:text="${order.amount}"></td>
</tr>
<script>
// Look for a link in the row and click on it
function orderRowClick(row) {
row.querySelector("a").click();
}
</script>
Several more points:
IDs must be unique in HTML. By putting id="orderRow" on such a repeated row will result in invalid HTML.
You shouldn't be using on... attributes to assign event handlers. I'm just using it here or otherwise this answer will go too far.
Remove the <form> from around the table. It doesn't do anything.
If you do want to/have to use a POST mapping, then replace the link in the table row with a form with a hidden field containing the order ID and a submit button and in the JavaScript look for the form instead of the link and submit it: row.querySelector("form").submit();.
BTW there are several (possibly better) ways to do what you are trying. For example:
Forget the JavaScript and just put a link into every cell. With the right CSS the row/cells can be changed so that it looks like you are clicking on the row.
It seems like you are using Bootstrap, which has the "stretched link" feature. Unfortunately it's a bit tricky to get to work with table rows, but it's worth looking at.
What I've understand so far is that you want to redirect user to a new page when the user clicks on the button on the table, for that there're different approaches -
Issue with your approach -
Since you're using ajax it wont be redirecting user to a new page ( because thats exactly how a AJAX works, for more info on AJAX us this link - https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX ), unless you explicitly tells your ajax-code to redirect the user on a new page.
For that you can simply put your page redirection code to a on your ajax success, something like this -
<script>
//your code
$.ajax({
// your code
success : function(data) {
//page redirection code here
window.location.href = "your-base-URL/restaurant/orderdetails/orderId="+orderId;
},
error : function() {
console.log("There was an error");
}
});
}
</script>
PS - This is not efficient programming practice since you're technically making an extra call to your server un-necessarily.
Approach 2nd
Simply make your html table buttin a-href link , like this -
<html>
// your code
<a th:href="#{'/restaurant/orderdetails/orderId=' + ${order.orderId}}">Order details button </a>
//your rest of the code
</html>
Approach-3rd , You can alternatively use java-script function for page redirection as well, simply modify you ajax function , something like this -
function getOrderItems(orderId) {
//page redirection code here
window.location.href = "your-base-URL/restaurant/orderdetails/orderId="+orderId;
}

Load automatically the rows in TabularForm Yii2

Iam trying to make this:
I need that when I create a new poll, it loads the aspects and a dropdown with the valorations choices list from the database like this:
I have a table for aspects, and another for valorations, which is a number from 1 to 5.
Normally, when I create a new poll i have to add manually all the rows and select the aspect and the valoration, but in this way its too much job, so i want it to load all the aspects and it would just need to set the valoration for each row and save it. thanks and sorry for my english
As far as I can understand your query, you want something like this:
You have a database table: Aspects (which I expect has static data)
You have a database table: valorat.(which I expect has static data of 1-5)
Now, whenever you create a new poll, it should automatically populate itself with the aspects and valoration dropdown table.
If I am right, you can try the following logic,
You can run the following logic
//run a loop for each aspect row fetched from database
<?php foreach($aspects as $value): ?>
<tr>
<td>
//here goes the id
</td>
<td>
<?= $value ?> //here goes your aspect value
</td>
<td>
<select>
//here run a loop for valorations you fetched from database
<?php foreach($valoration as $key=>$value): ?>
<option value="<?=$key?>"><?= $value ?></option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php endforeach; ?>
In this way, you can achieve the desired table with the aspects and valoration.
If you are using the Yii2 grid view, it is far more simple than this. But without looking at your code and database tables, I can't give you more.
Thank You!! I hope you will get some idea how to do this.

How to implement ZF2 View without using partialLoop view helper?

I have a pattern that I come across sufficiently often and I am looking for specifically a ZF2 (ZF3) way of solving this somewhat N + 1-related issue.
The following are excerpts from a single PHP file:
Looping through DB records & building table rows with data
Some number (say N) table rows are printed:
<?php
for ($i = 0; $i < db_num_rows($result); $i ++)
{
$row = db_fetch_array($result);
?>
<tr onclick="js_action(<?=$row['id']?>)">
<td><?=$row['number']></td>
<td><?=$row['company']?></td>
</tr>
<? } ?>
A single embedded JS Script that needs to be printed only once
<script type="text/javascript">
function js_action(id)
{
// some JS code
}
</script>
Question
I want to separate view generation from DB, and my main concern here is . . . do I use partialLoop view helper or skip it out entirely?
I can use partialLoop which will have me create files like this:
//controller
$this->partialLoop('filename', $arrayRows);
<!-- view -->
<td>$this->number</td>
<td>$this->company</td>
I don't see a point of creating a file so small just for this little loop. What is a good way to implement the View Script in my case?
The primary use-case for partialLoop is already mentioned in the documentation (emphasis added):
The primary use is for reusable template fragments
The only reason to split markup into another template is for reusability. If you don't need to reuse the markup, there is no reason to do the extra mile and defining an extra template. This makes reading & maintaining the template only harder.
Instead it is perfectly fine to use a foreach loop in your view:
<script type="text/javascript">
function js_action(id)
{
// some JS code
}
</script>
<table>
<?php foreach ($this->arrowRows as $row) { ?>
<tr>
<td><?php echo $row['number']; ?></td>
<td><?php echo $row['company']; ?></td>
</tr>
<?php } ?>
</table>
Even when you have this snippet arround a couple of times, it might make sense to keep it in place instead of creating a such small view script. For me it would seem like over-optimization.
I usually follow these principles:
Only move something into a seperate template when I reuse it more than 2-3 times
Only move code that contains more complex logic that echoing some values into simple markup (e.g. conditional rendering)
Simple markup can always be embedded even when it is re-used (e.g. simple tables with few classes)
Never try to generalize partials where the parent view defines the behavior of the markup (e.g. the view defines extra classes to be used in the partial). This usually ends of making everything more complex and coupled than being helpfull.

ngtable filters not working

I am trying to implement ngtable in order to have out of the box filters and pagination but it seems not to be as easy to implement as they say.
My data is loading correctly in the table, however the actual filters are not responding at all. Below is my table code inside the MyCtrl:
<table ng-table="tableParams" class="table table-condensed table-bordered table-striped">
<tr ng-repeat="movie in items.movies">
<td data-title="'Title'" filter="{ title: 'text'}" sortable="'title'">{{movie.title}}</td>
<td data-title="'Duration'" filter="{duration: 'number'}" sortable="'duration'">{{movie.duration | durationFilter | date:'HH:mm:ss'}} hrs</td>
</tr>
</table>
In the app.js I serve data factory to the controller then trigger the ng table:
app.controller('MyCtrl', function($scope, itemsFactory){
itemsFactory.getItems().success(function(data){
$scope.items = data;
tableParams = new NgTableParams({}, { data: data});
});
});
The result is that all the data is displayed and the input filters above the content, however, neither work. Is there something I am missing?
Supposing your HTML contains something like <table ng-table="tableParams", you want to assign your new NgTableParams to $scope.tableParams so the table can see them. Currently you are assigning a local variable.
Also, enable Javascript strict mode by "use strict". Avoids errors like that.
try to change your code
<tr ng-repeat="movie in items.movies">
to
<tr ng-repeat="movie in $data">

Is it good to call a model function from a view

While working on codeigniter, I sorted out one thing that I can call model function from view page also.
For an example
here's my example model
<?php
class autoload_model extends CI_Model{
function __construct() {
parent::__construct();
}
/*---------data fetching-----------*/
function get_data_from_table($table,$data,$cond)
{
$this->db->select($data);
$this->db->where($cond);
$result= $this->db->get($table);
return $result;
}
/*---------ends-----------*/
}
?>
Now in my view page i have written this
<table cellspacing="1" cellpadding="0">
<tr>
<td>Product Title</td>
<td><Product Price</td>
</tr>
<?php
$product_list = $this->autoload_model->get_data_from_table("td_product","*",
"product_id > 0")->result_array();
if(count($product_list)>0)
{
foreach($product_list as $pl)
{?>
<tr>
<td><?php echo $pl['product_title'];?></td>
<td><?php echo $pl['product_price'];?></td>
</tr>
<?php
}
}
else
{?>
<tr>
<td colspan="2">No data Found</td>
</tr>
<?php
}
}?>
</table>
the whole things works fine, its just that I want to know whether its good to use in such fashion or not?
NOTE:
The autoload model is automaticaly loaded in the config/autoload.php file
Codeigniter is PHP Framework which built on top of the MVC (Model - View - Controller) design pattern. if you do not follow this then do not use framework
In one word: NO.
Why?
1) Since codeigniter is a MVC Framework, we should follow some defined protocols of MVC.
2) We've to see that how a MVC Framework works and accordingly we've to use it.
3) So how CI works?
- Firstly, we have a URL which loads a particular page.
- The routes checks the routes matching the URL and calls particular Controller.
- If no match found in routes, it then checks the matching Controller and Function
- Controller calls the model with addon data, and models uses that data for database operations.
- Models then returns required data back to the Controller and then Controller loads the view using that data.
CI Flow:
Request ---> Routing ---> Controller ---> Model/Libraries/Helpers/Plugins ---> Controller ---> Views
Your answer:
1) Calling models in views will work anyways (if model is autoloaded) but still it's wrong. Doing that means we're breaking MVC rules.
2) Also you can see in above flow that there is no connection between models and views.
3) So where can we call models: controllers, libraries, helpers.
so another way of looking at this - you are calling the view to render a product table - but you have not confirmed whether there are products.
the controller calls a product model and requests products. if products come back then the controller assigns an appropriate view for displaying products and passes the products_list object (or array) to the view. there should not be any code in the middle of a table in a view like
if(count($product_list)>0)
the only php code the view should have is things like
foreach($product_list as $pl)
to display the products. the value of $product_list comes from the model. so if for example your database table name changes -- that change is done in the model -- not the view.
and if NO products come back from the model - then there is no $product_list. the controller assigns a view where the user can search/browse for other products. we don't need an if(count) in the view because we already know what the search results are.

Resources