g:select using two combobox in grails - mysql

Hi I'm trying to list shops using two dropdown combobox. İf you're not select country or city list all shops. Other way list according to city country or both of them. By the way I didn't create controller I generate tehm using generate-all.
here is my view;
<g:form action="index" method="POST">
<div class="fieldcontain">
<g:select name="ddlCountry" noSelection="[null:message(code:'default.select.label',default:'Seçiniz...')]"
from="['UK', 'NL', 'DE']"
value="${params.ddlCountry}"/>
<g:select name="ddlCity"
from="['AMSTERDAM', 'Erfurt', 'Manchester','London']"
value="${params.ddlCity}"/>
<input class="btn btn-danger" type="submit" value="Listele" />
<g:each in="${shopList}" status="i" var="shopInstance">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td>
<g:link controller="shop" action="show" params="[id:shopInstance.id]">
${fieldValue(bean: shopInstance, field: "shopName")}
</g:link>
</td>
<td>${fieldValue(bean: shopInstance, field: "shopAdress1")}</td>
<td>${fieldValue(bean: shopInstance, field: "shopPostcode")}</td>
<td>${fieldValue(bean: shopInstance, field: "shopCity")}</td>
<td>${fieldValue(bean: shopInstance, field: "shopCountry")}</td>
<td>${fieldValue(bean: shopInstance, field: "shopDateEdited")}</td>
</tr>
</g:each>
</div>
</g:form>
and here is Shop controller index
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
if(params.ddlCountry || params.ddlCity) {
def shops = Shop.withCriteria {
if (params.ddlCountry) {
like('shopCountry', '%${params.ddlCountry}%')
}
if (params.ddlCity) {
like('shopCity', '%${params.ddlCity}%')
}
}
[shopList:shops]
}
else{
respond Shop.list(params), model:[shopCount: Shop.count()]
}
}
It's listed all shops every time. When I click button page is refreshing but nothing happening

Seems like there is a lot to learn:
Create a new template/file inside myController folder called _index.gsp
inside it put this bit
<g:each in="${shopList}" status="i" var="shopInstance">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td>
<g:link controller="shop" action="show" params="[id:shopInstance.id]">
${fieldValue(bean: shopInstance, field: "shopName")}
</g:link>
</td>
<td>${fieldValue(bean: shopInstance, field: "shopAdress1")}</td>
<td>${fieldValue(bean: shopInstance, field: "shopPostcode")}</td>
<td>${fieldValue(bean: shopInstance, field: "shopCity")}</td>
<td>${fieldValue(bean: shopInstance, field: "shopCountry")}</td>
<td>${fieldValue(bean: shopInstance, field: "shopDateEdited")}</td>
</tr>
</g:each>
Change this to:
<!-- add onChange function to select you could look up item on change through jquery instead-->
<g:select name="ddlCity"
from="['AMSTERDAM', 'Erfurt', 'Manchester','London']"
value="${params.ddlCity}" onChange="verifyCity(this.value)"/>
<input class="btn btn-danger" type="submit" value="Listele" />
<!-- put a wrapper div ID around actual results -->
<div id="results">
<!-- make it render template now the controller action renders same content for this bit -->
<g:render template="/myController/index" />
</div>
<!-- END Wrapper -->
</div>
<script>
//Write some java script to handle the actions clicked
//VerifyCity will work on city click
//Hopefully this should be all it needs it gets a value builds a data array passes it to load results
function verifyCity(value) {
//
var data={ddlCity:value}
loadResults(data);
}
//Same as above for country
function verifyCountry(value) {
var data={ddlCountry:value}
loadResults(data);
}
//This runs a jquery post to the CONTROLLERNAME - define this and your action
//when it has a success it updates results DIV with the content
function loadResults(data) {
$.ajax({timeout:1000,cache:true,type: 'post',url: "${g.createLink(controller: 'CONTROLLERNAME', action: 'index')}",
data:data,
success: function(output) {
$('#results').html(output);
}
});
</script>
The segment that displayed results now in its own template, when it renders normally it calls in template. When ajax call is made it renders that specific template.
Now some changes to your controller
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
if(params.ddlCountry || params.ddlCity) {
def shops = Shop.withCriteria {
if (params.ddlCountry) {
like('shopCountry', '%${params.ddlCountry}%')
}
if (params.ddlCity) {
like('shopCity', '%${params.ddlCity}%')
}
}
//If request is coming in via ajax load in a template of the actual results so the bit that is within div id='results' should be actually a template.
if (request.xhr) {
render (template: 'myController/index', model:[shopList:shops])
return
}
//This will handle non ajax calls and will load in the index.gsp which includes the site mesh
[shopList:shops]
return
}
//no need for else just use return to stop a if statement in a controller
respond Shop.list(params), model:[shopCount: Shop.count()]
return
}
The controller will behave as it normally did with the exception of if if (request.xhr) which tells the controller if this is an ajax call render template _index.gsp rather than index.gsp
The difference between those two are that index.gsp has layout="main" this is the sitemesh that loads in the styles of the site. the template is plain and can be overloaded a segment of an existing normal page rendered.

Related

Laravel pass id to my sql on button click from view

I am trying to activate or deactivate the products for a form using $product->status
The active button shows if $product->status is 0 and
The deactive button shows if $product->status is 1
I want to toggle the value of $product->status in the mysql database every time I click on the button
<form action="{{route('invetory.create')}}" method="POST">
#csrf
<table class="table table-bordered" id="dynamicTable">
<tr>
<th>item</th>
<th>tax</th>
<th>Action</th>
</tr>
#forelse($products as $product)
<input type="text" name="item" value="{{$product->id}}
class="form-control" hidden />
<td>
<input type="text" name="item" value="{{$product->item}}
class="form-control" />
</td>
<td>
<input type="text" name="tax" value="{{$product->tax}}
class="form-control" />
</td>
#if($product->status =='0')
<td>
<button type="button" data-id="{{ $product->id }}" class="btn btn-success remove-tr active_btn">active</button>
</td>
#else
<td>
<button type="button" data-id="{{ $product->id }}" class="btn btn-danger remove-tr deactive_btn">Deactive</button>
</td>
#endif
</table>
</form>
here i have given the route i have used
web.php
Route::post('/update', 'App\Http\Controllers\InventoryController#update')>name('invetory.update');
here i have added the controler i have used
InventoryController.php
public function update(Request $REQUEST){
dd($REQUEST->all());
Inventory::update( $REQUEST->invetory as $key => $value);
return redirect()->action([InventoryController::class, 'index']);
}
i am geting 500 error when i click button
You can achieve this using POST request which will refresh the page each time you toggle a product or you can use AJAX to do the change asynchronously. Using Javascript and AJAX would be the preferred way so you don't lose selected filters, pagination etc.
You don't need external packages to implement that, you can use JavaScript's fetch method. Also, instead of having 2 separate functions and routes, I would suggest having one route that would toggle the product's status, i.e. if it is active, make it inactive and vice versa. That method by definition should be a POST request, by I prefer doing GET requests for this in order to avoid CSRF protection and use middleware to protect the request.
Here is the complete code.
Register a web route that toggles the state inside web.php
Route::get('projects/toggle', [ProjectController::class, 'toggle'])->name('projects.toggle');
Implement the toggle method in ProjectController.php
public function toggle(Request $request) {
$project = Project::find($request->project_id);
$project->status = !$project->status;
$project->save();
return response()->json(['status' => (int) $project->status]);
}
Notice that I am returning a json response which includes the new project status. We will use this in the JavaScript code to dinamically update the column where the status is shown.
Finally, in the blade file, when iterating through the projects, the button click calls a function that will do the AJAX request. Notice that I am also adding an id attribute to the columns that contains the status so I can access it dinamically in order to update it.
#foreach($projects as $project)
<tr>
<td>{{$project->title}}</td>
<td id="project-status-{{$project->id}}">{{$project->status}}</td>
<td><button onClick="toggleStatus('{{$project->id}}')">Toggle</button></td>
</tr>
#endforeach
In this same file, we add the following JavaScript code. It accepts project_id as parameter which is passed from the button click, makes the ajax request to backend which updates the status and then updates the appropriate DOM element to show the new status.
function toggleStatus(project_id) {
fetch("{{ route('projects.toggle') }}?project_id=" + project_id)
.then(response => response.json())
.then(response => {
document.querySelector("#project-status-" + project_id).innerHTML = response.status;
})
}
As I mentioned, you can use multiple options in the JavaScript part. Instead of calling a function you can register an event listener to each button, but this approach with function call is a bit quicker. Also, I am passing the project_id as GET parameter, you can define the route to contain it as route parameter, but then you'll need to do some string replacements in order to do in dinamically in JavaScript. All in all, the proposed is a good solution that will serve your purpose.
p.s. For stuff like this, LiveWire is a perfect fit.
Using dd (e.g. in your controller) will throw a 500 error. It literally stands for "dump and die".
check you routes in form use{{route('invetory.create')}}
and in routes you given inventory.update
public function Stauts(Request $request)
{
$product= Product::findOrFail($request->id);
$product->active == 1 ? $product->active = 0 : $product->active = 1 ;
$product->update();
return response()->json(['status' => true,'msg' => 'Staut updated']);
}
in blade use ajax
<script>
$(document).on('click', '.status-product', function (e) {
e.preventDefault();
var product_id = $(this).data('id');
var url ="{{ route('product.status') }}";
$.ajax({
type: "post",
url: url,
data: {
'_token': "{{csrf_token()}}",
'id': product_id
},
success: function (data) {
if (data.status == true) {
$('#deactive_ajax').show();}
}
})
})
</script>
Route::post('product/stauts/', [productController::class,'Stauts'])->name('product.Stauts');
First of all
Using a form with tables is not ideal and some browsers already made changes to prevent that.
Secondly
The best way is as DCodeMania said, the ajax request is the best way to solve this, I'll just modify his answer a bit and use Patch instead of PUT, so it'll look like this:
$(document).on('click', '.active_btn', function(e) {
e.preventDefault();
let id = $(this).data('id');
$.ajax({
url: '{{ route("products.update") }}',
method: 'PATCH',
data: {
id: id,
_token: '{{ csrf_token() }}'
},
success: function(response) {
console.log(response);
}
});
});
and you'll only be needing one button so no need to make the check for $product->status he added, just a single button for the toggle will make your code cleaner.
As for using PATCH instead of PUT, because you're only updating one single column and not the whole thing getting updated, and no need for the status parameter, you'll just reverse what's inside the database
$product = Product::find($request->id);
Product::where('id', $product->id)->update([
'status' => $product->status ? 0 : 1,
]);
You'll also need one button with different text based on status
like this
<td>
<button type="button" data-id="{{ $product->id }}" class="btn btn-success remove-tr active_btn">{{ $product->status == 1 ? 'deactivate' : 'activate' }}</button>
</td>
I did it this way and it works for me
First in view does this
<td>
#if ($producto->estado == '1')
<a href="{{ url('/status-update-producto', $producto->id) }}"
class="btn btn-success" id="btn_estado">Activo</a>
#else
<a href="{{ url('/status-update-producto', $producto->id) }}"
class="btn btn-danger" id='btn_estado'>Inactivo</a>
#endif
</td>
Controller
function updateStatusProducto($id)
{
//get producto status with the help of producto ID
$producto = DB::table('productos')
->select('estado')
->where('id', '=', $id,)
->first();
//Check producto status
if ($producto->estado == '1') {
$estado = '0';
} else {
$estado = '1';
}
//update producto status
$values = array('estado' => $estado);
DB::table('productos')->where('id', $id)->update($values);
return redirect()->route('productos.index');
}
Route
Route::get('/status-update-producto/{id}', [ProductoController::class, 'updateStatusProducto']);
You could add some data attributes to your buttons, and use them in js to send an ajax request
#if ($product->status =='0')
<td>
<button type="button" class="btn btn-success toggle-tr" data-product="{{ $product->id }}" data-status="{{ $product->status }}">active</button>
</td>
#else
<td>
<button type="button" class="btn btn-danger toggle-tr" data-product="{{ $product->id }}" data-status="{{ $product->status }}">Deactive</button>
</td>
#endif
document.querySelectorAll('.toggle-tr').forEach(el => el.addEventListener('click', e => {
const product = e.target.dataset.product;
const status = e.target.dataset.status == 0 ? 1 : 0;
// send ajax or fetch request passing in product_id. If we're going with a RESTful approach,
axiox.patch(`/products/${product}`, { status })
.then(res => { ... })
.catch(err => { ...});
}));
You can use jQuery ajax here:
Pass product id in data-id attribute
#if($product->status =='0')
<td>
<button type="button" data-id="{{ $product->id }}" class="btn btn-success remove-tr active_btn">active</button>
</td>
#else
<td>
<button type="button" data-id="{{ $product->id }}" class="btn btn-danger remove-tr deactive_btn">Deactive</button>
</td>
#endif
then use ajax:
$(document).on('click', '.active_btn', function(e) {
e.preventDefault();
let id = $(this).data('id');
$.ajax({
url: '{{ route("products.update") }}',
method: 'PUT',
data: {
id: id,
status: 1,
_token: '{{ csrf_token() }}'
},
success: function(response) {
console.log(response);
}
});
});
$(document).on('click', '.deactive_btn', function(e) {
e.preventDefault();
let id = $(this).data('id');
$.ajax({
url: '{{ route("products.update") }}',
method: 'PUT',
data: {
id: id,
status: 0,
_token: '{{ csrf_token() }}'
},
success: function(response) {
console.log(response);
}
});
});
Now you can handle the request in the controller.

Can I make HTTP POST request from Thymeleaf table in Spring Boot application

I have a Thymeleaf template in a simple Spring Boot application. The template contains a list in a table as follows:
<p>There are <span th:text="${#lists.size(persons)}"></span> people:</p>
<table th:if="${not #lists.isEmpty(persons)}" border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Address</th>
<th>Telephone</th>
<th>Email</th>
<th>Actions</th>
</tr>
<tr th:each="person : ${persons}">
<td th:text="${person.personId}"></td>
<td th:text="${person.name}"></td>
<td th:text="${person.address}"></td>
<td th:text="${person.telephone}"></td>
<td th:text="${person.email}"></td>
<td>
Edit |
Delete
</td>
</tr>
</table>
I want to enable edit and delete functionality as per the last cell in the table. But at the moment both requests are for HTTP GET. That is fine for edit where a person's details are fetched from the server for editing, but delete should trigger a POST request because of the data changes on the server.
Does anyone know if Thymeleaf allow a POST request per row of a table? Or do I have to write a simple HTML form per row?
The GET form is currently:
<td>
Edit
<!--a href="#" data-th-href="#{/delete(personId=${person.personId})}">Delete</a></td-->
<form method="get" th:action="#{/edit(personId=${person.personId})}">
<button type="submit" name="submit" value="value">Edit</button>
</form>
</td>
Where I have a link and a form for testing.
The controller method to be called is:
// Gets a Person.
#RequestMapping(value="/edit", method=RequestMethod.GET)
public String getEditPerson(#RequestParam("personId") String personId, Model model) {
logger.info(PersonController.class.getName() + ".getEditPerson() method called.");
Person person = personDAO.get(Integer.parseInt(personId));
model.addAttribute("person", person);
// Set view.
return "/edit";
}
The error when the button version of GET is called is:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sun Jul 24 00:26:16 BST 2016
There was an unexpected error (type=Bad Request, status=400).
Required String parameter 'personId' is not present`
I am using GET to trigger editing because no data is sent to the server here other than the personId. No database action is taken so it should be a GET.
you are using Links and I don't think that is possible, you would need to use a form where you can specify the method POST to be used.
In the example below im using a <button> instead of a <a> element, but it will work, the only thing you need to do is to style your button with CSS to look like your links
<form method="POST" th:action="#{/edit(personId=${person.personId})}">
<button type="submit" name="submit" value="value" class="link-button">This is a link that sends a POST request</button>
</form>
now in your code should look like this
<tr th:each="person : ${persons}">
<td th:text="${person.personId}"></td>
<td th:text="${person.name}"></td>
<td th:text="${person.address}"></td>
<td th:text="${person.telephone}"></td>
<td th:text="${person.email}"></td>
<td>
<form method="POST" th:action="#{/edit(personId=${person.personId})}">
<button type="submit" name="submit" value="value" class="link-button">EDIT</button>
</form> |
<form method="POST" th:action="#{/delete(personId=${person.personId})}">
<button type="submit" name="submit" value="value" class="link-button">DELETE</button>
</form>
</td>
</tr>
EDIT
As you just shared you Java code, in the controller you are expecting the personId not as a PathVariable, but as a RequestParam,
in that case your form should have that value...
edit your form and add the person id as follows.
<form method="POST" th:action="#{/edit}">
<input type="hidden" name="personid" id="personId" th:value="${person.personId}" />
<button type="submit" name="submit" value="value" class="link-button">This is a link that sends a POST request</button>
</form>
Notice also I changed the action of the form to be just /edit, as its what your controller looks like
Does anyone know if Thymeleaf allow a POST request per row of a table? Or do I have to write a simple HTML form per row?
HTML doesn't support POST request with links and you have to use forms (as Rayweb_on explained). But Thymeleaf allows you to define custom tags which helps a lot :
<a th:href="#{/edit(personId=${person.personId})}" custom:linkMethod="post">Edit</a>
... which would generate following HTML (assuming jQuery is available) :
Edit
Custom tag definition (without error checking to keep it simple) :
/**
* Custom attribute processor that allows to specify which method (get or post) is used on a standard link.
*/
public class LinkMethodAttrProcessor extends AbstractAttributeTagProcessor {
private static final String ATTR_NAME = "linkMethod";
private static final int PRECEDENCE = 10000;
public LinkMethodAttrProcessor(final String dialectPrefix) {
super(
TemplateMode.HTML, // This processor will apply only to HTML mode
dialectPrefix, // Prefix to be applied to name for matching
null, // No tag name: match any tag name
false, // No prefix to be applied to tag name
ATTR_NAME, // Name of the attribute that will be matched
true, // Apply dialect prefix to attribute name
PRECEDENCE, // Precedence (inside dialect's own precedence)
true); // Remove the matched attribute afterwards
}
#Override
protected void doProcess(final ITemplateContext context, final IProcessableElementTag tag,
final AttributeName attributeName, final String attributeValue,
final IElementTagStructureHandler structureHandler) {
// get the method name (tag parameter)
final IEngineConfiguration configuration = context.getConfiguration();
final IStandardExpressionParser parser = StandardExpressions.getExpressionParser(configuration);
final IStandardExpression expression = parser.parseExpression(context, attributeValue);
final String method = (String) expression.execute(context);
// add custom javascript to change link method
final String link = tag.getAttribute("href").getValue();
final String action = "$('<form action="" + link + "" method="" + method + ""></form>').appendTo('body').submit(); return false;";
structureHandler.setAttribute("onclick", action);
structureHandler.setAttribute("href", "#");
}
}
See the Thymelead documentation for example of how this custom attribute needs to be registered.

Get the parent index of the array angularjs

I searching and I found out that this code is what I need right now. But there is something wrong about it. When I clicked the alertme button it's alert is -1 which is wrong. When I click 1 Brick med it's alert -1 it should be 0 because the no and name is in sectionA. When I want t click 3 Frank Joemar Timbang it should alert 1 because he is in sectionB? Aney help? suggestions? TIA
var stud = angular.module("stud", []);
stud.controller("StudentsController", function ($scope) {
'use strict';
$scope.alertMe = function (studentGroup) {
alert($scope.students.indexOf(studentGroup));
};
$scope.sectionA = [
{
no:1,
name:'Brick Med',
},
{
no:2,
name: 'Colin Christopher',
},
];
$scope.sectionB = [
{
no:3,
name: 'Frank Joemar Timbang',
},
{
no:4,
name: 'Curtis Zaymond',
}
];
$scope.students = [
$scope.sectionA,
$scope.sectionB
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html data-ng-app="stud">
<head lang="en">
<meta charset="utf-8">
<title>Students</title>
</head>
<body data-ng-controller="StudentsController" data-ng-init="init()">
<div id="container">
</div>
<div class="container-table">
<table border="1" width="100%">
<thead>
<tr>
<td>Students</td>
<td>Alert</td>
</tr>
</thead>
<tbody ng-repeat="studentGroup in students">
<tr ng-repeat="student in studentGroup">
<td>{{student.no}} {{student.name}}</td>
<td><button ng-click="alertMe($parent.$index)">Alert me!</button></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
Okay so your problem is that you are using indexOf() when you want to just be using studentGroup as the index.
$scope.alertMe = function (studentGroup) {
alert($scope.students[studentGroup]); // returns object object in your array
alert($scope.students[studentGroup][0]); /// returns sectionA object1
alert($scope.students[studentGroup][0].name); /// returns sectionA object1 name
};
And I fixed up your html so it is easier to read but your original stuff should still work.
<tbody ng-repeat="studentGroup in students" ng-init="studentsIndex = $index">
<tr ng-repeat="student in studentGroup">
<td>{{student.no}} {{student.name}}</td>
<td><button ng-click="alertMe(studentsIndex)">Alert me!</button></td>
</tr>
</tbody>
If this isn't what you want and you really want to alert the index, let me explain how indexOf works. That method will take a search parameter, and that is used to search an array for that element data. It is returning -1 right now because you give it the index and it searches for that index as the element data in index 0 and 1. Steps: Does whatever index = $scope.sectionA , Nope move on, Does whatever index = $scope.sectionB, nope move on. Done, did not find search parameter return -1.
The problem is with the indexOf. studentGroup is set correctly to 0 for the first 2 rows and 1 for the next 2. If you want the section array you should use
$scope.alertMe = function (studentGroup) {
alert($scope.students[studentGroup]);
};

Angular.js Infinite Loop of calling functions

My problem is in the following template :
<div class="container">
<h1>Process Definitions</h1>
<table class="table table-stripped" >
<tr>
<td><strong>Name</strong></td>
<td><strong>Id</strong></td>
<td><strong>Version</strong></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr ng-repeat="def in defs | filter: global.search">
<td>{{def.name}}</td>
<td>{{def.id}}</td>
<td>{{def.version}}</td>
<td><button type="button" class="btn btn-warning" ng-click="redirectToInstance(def.id)">Instances</td>
<!--<td><h4><small>{{'Current :' + getCount(def.id) }}</small></h4></td>-->
<td><button type="button" class="btn btn-warning" ng-click="redirectToTasks(def.id)">Tasks</td>
</tr>
</table>
</div>
The problem is the function call inside the expression inside the comment-tag.
the function called is in this controller :
BPMNControllers.controller('ProcessDefinitionCtrl', ['$scope','$location', 'ProcessDefinitions','ProcessInstances',
function($scope,$location, ProcessDefinitions,ProcessInstances) {
$scope.defs = ProcessDefinitions.query();
$scope.redirectToInstance = function(id){$location.path('/process-definitions/' + id);};
$scope.redirectToTasks = function(id){$location.path('/tasks/def'+id)};
$scope.getCount = function (id){
var countObj = ProcessInstances.getCount({processDefinitionId : id});
return countObj.count;
};
console.log('ProcessDefinitionCtrl');
}]);
And the following service is important, cause it's querying a rest-api.
BPMNServices.factory('ProcessInstances', ['$resource','restUrl',
function($resource,restUrl){
var url = restUrl+'engine-rest/process-instance/:id'
return $resource(url,{id:'#id'},{
query : {method:'GET',isArray:true},
get : {method:'GET'},
getCount : {method:'GET',url:restUrl+'engine-rest/process-instance/count'}
},{})
}]);
This results in an infinite loop of ajax calls.I think i know that the problem is the asynchronous call, and since it's not directly bound the call is not fast enough and thus called and called again. How can i do this?
And the ProcessDefinitions as requested:
BPMNServices.factory('ProcessDefinitions', ['$resource','restUrl',
function($resource,restUrl){
var url = restUrl + 'engine-rest/process-definition/:id'
return $resource(url, {id : '#id'}, {
query: {method:'GET', isArray:true},
get : {method:'GET'},
start: {method:'POST',url:url+'/start'}
},{});
}]);
And the model for the global search filter :
<input type="text" class="form-control" placeholder="Search" ng-model="global.search">
The infinite loop is a result of your watched view expression calling a function which itself results in the triggering of a $digest cycle.
A good explanation, and another example, is provided in Infinite loop with Angular expression binding
As for your particular code, you could use a directive in place of the view expression:
HTML
<!-- results in infinite digest Count: {{getCount(def.id)}} -->
Count: <count></count>
JS
.directive('count', function(ProcessInstances){
return {
restrict: 'E',
replace: true,
link: function(scope) {
scope.countRes = ProcessInstances.getCount(scope.def.id);
},
template: '<span>{{countRes.count}}</span>'
}
});
Demo

PartialViews - Not Using Shared Site.css in Editor/Display Templates - ASP.NET MVC 3

I'm using the JQuery UI Tabs functionality in my Open Source Project. I'm doing this to learn MVC3 (And various other technologies). Now I've got that all working. The problem is my Partial Views within each tab have links off the the relevant CRUD functionality. I've set these CRUD views up as Display and Editor Templates. Its these that are not picking up the _Layout.cshtml references to the Site.css.
EDIT START
I've found in the "Add View" scaffolding functionality that when you click the Create as a partial view box that the master page functionality disappears, ie greys out, BUT in Razor I thought if this is empty it uses the _viewstart file, which loads the_Layout?
EDIT END
Here is my Dashboard.cshtml code with the JQuery UI Tab logic:
<script type="text/javascript">
$(document).ready(function() {
$("#tabs").tabs();
getContentTab (1);
});
function getContentTab(index) {
var url='#Url.Content("~/SiteAdmin/AjaxGetTab")/' + index;
var targetDiv = "#tabs-" + index;
var ajaxLoading = "<img id='ajax-loader' src='#Url.Content("~/Content")/ajax- loader.gif' align='left' height='28' width='28'>";
$(targetDiv).html("<p>" + ajaxLoading + " Loading...</p>");
$.ajax({
type: 'get',
url: url,
cache: false,
success: function(result) {
$(targetDiv).html(result);
}
});
}
<div id="tabs">
<ul>
<li>Transaction Type </li>
<li>Direction Type</li>
<li>User Type</li>
<li>Currency Type</li>
</ul>
<div id="tabs-1">
</div>
<div id="tabs-2">
</div>
<div id="tabs-3">
</div>
<div id="tabs-4">
</div>
</div>
Here is my AjaxGetTab Action Method if you need to know how i decide to create tabs and create the list objects:
/// <summary>
/// AJAX action method to obtain the correct Tab to use.
/// </summary>
/// <param name="index">Tab number</param>
/// <returns>Partial View</returns>
public ActionResult AjaxGetTab(int id)
{
string partialViewName = string.Empty;
object model = null;
//--Decide which view and model to pass back.
switch (id)
{
case 1:
partialViewName = "_TransactionType";
model = db.TransactionTypes.ToList();
break;
case 2:
partialViewName = "_DirectionType";
model = db.DirectionTypes.ToList();
break;
case 3:
partialViewName = "_UserType";
model = db.UserTypes.ToList();
break;
case 4:
partialViewName = "_CurrencyType";
model = db.CurrencyTypes.ToList();
break;
case 5:
partialViewName = "_tabError";
break;
}
return PartialView(partialViewName,model);
}
At the moment I'm working on TransactionType so here is the _TransctionType.cshtml code for the PartialView:
#model IEnumerable<Accounts.Models.TransactionType>
<p>
#Html.ActionLink("Create New", "CreateTransactionType")
</p>
<table>
<tr>
<th>
Record Status
</th>
<th>
Description
</th>
<th>
Created Date
</th>
<th>
Amended Date
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.RecordStatus)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td>
#Html.DisplayFor(modelItem => item.CreatedDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.AmendedDate)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.id }) |
#Html.ActionLink("Details", "Details", new { id=item.id }) |
#Html.ActionLink("Delete", "Delete", new { id = item.id })
</td>
</tr>
}
Now the "Edit" & Delete ActionLink has an EditorTemplate and the Details has a DisplayTemplate folder with the required TransactionType.cshtml Its these views which the _Layout Site.css isnt being applied to. Here is example code from the "Edit" code base:
_EditTransactionType.cshtml:
#model Accounts.Models.TransactionType
#using (Html.BeginForm())
{
#Html.EditorForModel()
<p>
<input type="submit" value="Save" />
</p>
}
And here is the TransactionType.cshtml which sits in /Views/SiteAdmin/EditorTemplate:
#model Accounts.Models.TransactionType
<fieldset>
<legend>Transaction Type</legend>
<div class="editor-label">
#Html.LabelFor(model => model.RecordStatus)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.RecordStatus)
#Html.ValidationMessageFor(model => model.RecordStatus)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
</fieldset>
Now I could just put a reference to the Site.css in each Template, but is there a cleaner way of doing this? Am I missing something?
_ViewStart is only applied to Views that are rendered, this is determined on how you render the view. E.G using RenderPartial or returning a PartialView from a controller returns only the contents (and nest partials) of the PartialView that you are targetting.
If the _LayoutFile applied to every view and every partial view then you would end up with pages like so:
<html>
<head />
<body>
<html>
<head />
<body>
<!-- Actual Partial View Content -->
</body>
</html>
</body>
</html>
When a page is rendered all of the the _layout, the view to be rendered, any partial views and any nest partials or editor/display templates are built into a single page and returned to the client so any style sheets that are referenced by the _Layout master will be applied to this now flattened heirarchy of (Partial)Views.
Have you inspected the output HTML to make sure that is as expected? It may not be a problem with the views.
I really don't see why you complicated using jqueryui tabs so much adding onclick then a switch etc.
<div id="tabs">
<ul>
<li><span>Transaction Type</span></li>
<li><span>Direction Type</span></li>
<li><span>User Type</span></li>
<li><span>Currency Type</span></li>
</ul>
</div>
<script type="text/javascript">
$(document).ready(function () {
$('#tabs').tabs({
spinner: '<img src="../../Content/Images/tabsppinner.gif" alt="" /> #Loading...'
});
});
</script>
Then you would just have one controller with actions defined for every tab.