How to create a custom directive for ng-table (using different data for the table and ng-repeat) - angularjs-ng-repeat

I am a little stuck trying to create a custom directive for ng-table.
In my application I have multiple times the table "users".
I have a main table that displays all the users, and I also have some custom tables that displays a limited number of users.
These custom data for the tables is created into the controllers and have different names (usersList1, usersList2 etc.).
The tables are identical (header, columns labels), only the data inside changes.
I would like to have a custom directive and to pass to it the data to display.
Here is my code:
.directive('tableForListingDirective', function () {
return {
restrict: 'EA',
scope: true,
template: [
'<table ng-table="tableParams" class="table table-striped table-bordered table-hover" template-pagination="custom/pager">',
'<tr ng-repeat="user in tableData">',
'<td width="30" style="text-align: left" header="\'ng-table/headers/checkbox.html\'"> <input type="checkbox" ng-model="user.checked" ng-change="toggleCheckedUserToAdd(user)"/>',
'<td data-title="\'Status\'" sortable="\'status\'">{{user.status}}</td>',
'<td data-title="\'Login\'" sortable="\'login\'">{{user.login}}</td>',
'<td data-title="\'Name\'" sortable="\'name\'">{{user.name}}</td>',
'<td data-title="\'Email\'" sortable="\'email\'">{{user.email}}</td>',
'</tr>',
'</table>'
].join(''),
link: function (scope, element, attrs) {
scope.tableData=scope.$eval(attrs.tableData);
},
}
});
Call in the html file:
<table-for-listing-directive table-data="{{users}}"></table-for-listing-directive>
You may say, why didn't I put the tableData: "=" into the scope.
Well, after some long hours of searching I discovered that ng-repeat and scope{} don't want to work with each other, so in order to make the ng-repeat work inside the directive I have to say 'scope: true'.
Inside ng-repeat I tried to make ng-repeat="user in {{tableData}}" it doesn't work either.

In your HTML change table-data="{{users}}" with table-data="users"

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;
}

MVC consideration in 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.

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">

Meteor - Return HTML Template via ajax

I would like to display a template generated in my Meteor app on another website.
I had hoped to use an ajax call in the website to fetch the relevant meteor template and data, but I am struggling.
the website makes the call as follows:
<body>
<div id="result">
</div>
</body>
<script>
$( "#result" ).load( "http://myMeteorApp/get_template" );
</script>
In the Meteor app I have tried to return the template using iron-router:
Router.map(function () {
this.route('get_template', {
where: 'server',
path: 'get_template',
action: function () {
return 'get_template'
}
})
The template 'get_template.html' is in the 'private' folder.
<template name="get_template">
<table class="table table-hover table-condensed">
<tr>
<th>Name</th>
<th>Email</th>
<th>Mobile</th>
</tr>
{{#each members}}
<tr>
<td>{{first_name}} {{last_name}}</td>
<td>{{email}}</td>
<td>{{mobile}}</td>
</tr>
{{/each}}
</table>
This does not work and I have a feeling I am barking up the wrong tree.
Maybe I ought to be using an iframe? But I prefer for the Meteor app to behave like an API and simply return the template.
Help appreciated.
https://github.com/EventedMind/iron-router#server-side-routing:
Server action functions (RouteControllers) have different properties
and methods available. Namely, there is no rendering on the server
yet.
Also, even if that was working there is a lot missing in your javascript:
You don't seem to specify anywhere the data to use in the template
The action function returns a string. What is this supposed to do?
I think your best bet is to use a server-side template engine such as meteor-handlebars-server and just manually render the template:
Router.map(function () {
this.route('serverFile', {
where: 'server',
path: '/get_template/:templatename',
action: function () {
var templatename = this.params.templatename;
this.response.writeHead(200, {'Content-Type': 'text/html'});
this.response.end(Handlebars.templates[templatename]({members: []}));
}
});
});
Inserting the data in the members field of the supplied object.

Resources