I am using angular-datatables plugin to add datatables to my project. In this, I have a column Actions where I want to add some buttons. For this, I am using ng-template which is defined on the same page. The problem is that the template does not always render. It sometimes shows the button, and sometimes it does not. It never shows the buttons after I make a search.
controller
$scope.dtOptions = DTOptionsBuilder.newOptions().withOption('ajax', {
url: '/api/department',
type: 'GET'
})
.withDataProp('data')
.withOption('processing', true)
.withOption('serverSide', true)
.withPaginationType('full_numbers')
.withOption('createdRow', function (row, data, dataIndex) {
// Recompiling so we can bind Angular directive to the DT
$compile(angular.element(row).contents())($scope);
})
.withBootstrap();
$scope.dtColumns = [
DTColumnBuilder.newColumn('id').withTitle('ID'),
DTColumnBuilder.newColumn('name').withTitle('Name'),
DTColumnBuilder.newColumn('actions').withTitle('Actions').withOption("searchable", false)
];
view
<script type="text/ng-template" id="actions.html">
<button class="btn btn-primary btn-xs" ng-click="edit()"><i class="fa fa-edit"></i> Edit</button>
<button class="btn btn-danger btn-xs" ng-click="delete()"><i class="fa fa-trash"></i> Delete</button>
</script>
<div class="hbox hbox-auto-xs hbox-auto-sm" ng-controller="DepartmentsController">
<div class="bg-light lter b-b wrapper-md">
<h1 class="m-n font-thin h3">Departments</h1>
</div>
<div class="wrapper-md">
<div class="panel panel-default">
<div class="panel-body">
<div class="row">
<div class="col-xs-6">
<button class="btn m-b-md btn-md btn-primary " ui-sref="manager.departments.create">
<i class="fa fa-plus"></i> <span class="hidden-sm hidden-xs">Add Department</span></button>
</div>
</div>
<div class="row">
<div class="col-sm-12 m-b-xs">
<table datatable="" dt-options="dtOptions" dt-columns="dtColumns" class="table table-striped b-t b-b">
<thead>
<tr>
<th style="width:20%">ID</th>
<th style="width:60%">Name</th>
<th style="width:20%">Actions</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
controller on server side in Laravel
public function index() {
$departments = Department::company($this->company->id)
->select("departments.id", "departments.name");
return \Datatables::of($departments)
->add_column("actions", function($row) {
return '<div ng-include src="\'actions.html\'"></div>';
})
->make(true);
}
I belive this is some syncronization issue. But, I am not getting anywhere.
Do you really get any successfully inserted templates? The only way I can get $compile(angular.element(row).contents())($scope) to work is when the <table> is prebuilt or rendered by ng-repeat.
Here delayed injected HTML from a jQuery AJAX needs to be replaced with a ng-template including bindings, I think $scope.$apply() is the only way around :
.withOption('createdRow', function (row, data, dataIndex) {
$scope.$apply($compile(angular.element(row).contents())($scope))
})
Works for me -> http://plnkr.co/edit/UqZKhpgMx7aHCXdaNkiN?p=preview
Silly me. The same can be done in a simple $timeout.
$timeout(function() {
$compile(angular.element(row).contents())($scope)
})
http://plnkr.co/edit/5OTeHHUgkIurd6Z3DCkP?p=preview
Related
i'm trying to add a new entered value to a table after success method runs using ajax , i've used ModelForm . i want to add the new entry to the table body row ! , i've tried alot , but still i cant figure it out ! i most appreciate your helps
class MainGroup(models.Model):
admin = models.ForeignKey(User,on_delete=models.CASCADE)
main_type = models.CharField(max_length=40,unique=True)
date = models.DateTimeField(auto_now_add=True)
my views.py
#login_required
def create_maingroup(request):
lists = MainGroup.objects.all().order_by('-pk')
form = MainGroupForm()
if request.is_ajax() and request.method == 'POST':
form = MainGroupForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.admin = request.user
obj.save()
return JsonResponse({'success':'success'})
else:
return JsonResponse({'sucess':False,'error_msg':form.errors,'error_code':'invalid'})
context = {
'form':form,'lists':lists
}
return render(request,'products/create_maingroup.html',context)
const form = document.getElementById('main_form')
form.addEventListener("submit",submitHandler);
function submitHandler(e) {
e.preventDefault();
$.ajax({
type: 'POST',
url: '{% url 'products:create-maingroup' %}',
data : $('#main_form').serialize(),
dataType: 'json',
success: successFunction,
});
}
function successFunction(data) {
console.log(data.success=='success')
if (data.success=='success') {
form.reset();
obj = $('#main_form').serialize();
//i have to append new entred values here
//but i dont know how to get inputs and set the admin
//name who created the post !
alertify.success("added")
}
else if(data.error_code=='invalid'){
for(var key in data.error_msg){
if(key == 'main_type'){
document.getElementById('main_error').removeAttribute('hidden')
document.getElementById('main_error').innerHTML = data.error_msg[key][0]
}
}
}
}
my html page
<div class="col-md-12">
<div class="card card-info">
<div class="card-header">
<div class="card-tools">
<button type="button" class="btn btn-tool" data-toggle="collapse" data-target="#main_form" aria-expanded="false" aria-controls="main_form">
<i class="fas fa-minus"></i>
</button>
</div>
<h3 class="text-center">add new data</h3>
</div>
<!-- /.card-header -->
<!-- form start -->
<form id="main_form" role="form" method="POST">{% csrf_token %}
<div class="card-body">
<div class="form-group row">
<label for="mainGroup" class="col-sm-2 control-label">name</label>
<div class="col-sm-10">
{{form.main_type | attr:'id:mainGroup'}}
<p id="main_error" class="alert alert-danger" aria-disabled="true" hidden></p>
</div>
</div>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-success">add</button>
</div>
</form>
</div>
</div>
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h3 class="text-center">list of names</h3>
</div>
<div class="card-body table-responsive">
<table id="maingroupid" class="table table-bordered table-striped text-center">
<thead>
<tr>
<th>#</th>
<th>admin</th>
<th>name</th>
<th>date</th>
<th>actions</th>
</tr>
</thead>
<tbody id="tableData">
{% for i in lists %}
<tr>
<td>{{forloop.counter}}</td>
<td>{{i.admin}}</td>
<td>{{i.main_type}}</td>
<td>{{i.date | date:'d-m-Y h:i A'}}</td>
<td align="center">
<button class="btn btn-info bg-info" onclick="editMain({{i.id}})" data-toggle="modal" data-target="#myModal"><i class="far fa-edit"></i></button>
<button class="btn btn-danger bg-danger" onclick="deleteMain({{i.id}})"><i class="far fa-trash"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</tfoot>
</table>
</div>
</div>
</div>
is it possible without refreshing the page and display the new data please ? i need it so much
You could return the new table once edited
context = {} # whatever your context is
return render(request, 'path/to/table/template.html', context=context)
template.html is the table element of your template
<thead>
<tr>
<th>#</th>
<th>admin</th>
<th>name</th>
<th>date</th>
<th>actions</th>
</tr>
</thead>
<tbody id="tableData">
{% for i in lists %}
<tr>
<td>{{forloop.counter}}</td>
<td>{{i.admin}}</td>
<td>{{i.main_type}}</td>
<td>{{i.date | date:'d-m-Y h:i A'}}</td>
<td align="center">
<button class="btn btn-info bg-info" onclick="editMain({{i.id}})" data-toggle="modal" data-target="#myModal"><i class="far fa-edit"></i></button>
<button class="btn btn-danger bg-danger" onclick="deleteMain({{i.id}})"><i class="far fa-trash"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</tfoot>
Then on success within ajax use
success: function (data, status) {
$('#maingroupid`).html(data);
}
I Have the following code cshtml
<div class="container-fluid" id="dvUserData">
<div class="tab-pane fade" id="documentos" role="tabpanel" aria-labelledby="documentos-tab">
#Html.Partial("Documentos")
<div class="col-md-3">
<button type="submit" class="btn btn-primary botao-vert" data-bind="click: editData">SALVAR</button>
</div>
</div>
and the following binding
ko.applyBindings(model, document.getElementById("dvUserData"));
But my data-bind="click: editData" does not work, the click is not performed. But if i put the div class="col-md-3" before the #Html.Partial("Documentos") the bindings work.
I have no idea why, I looked for posts here but could not find anything similar.
Thanks in advance for any help.
---EDITED
The Partial
<div class="row" id="dvDocument">
<form role="form">
<div class="row">
<div class="col-12">
<table class="table tabela-documentos">
<tbody data-bind="foreach: documentsReturn().documentTypes">
<tr class="bg-cinza">
<td>
<div class="aviso-sucesso" data-bind="visible : hasAllDocuments()"></div>
<div class="aviso-critica" data-bind="visible : !hasAllDocuments()"></div> <span data-bind="text: Description"></span>
</td>
<td>
<span class="d-none" data-bind="value: IdTypeDocument"></span>
<a class="btn btn-secondary" data-bind="click: function () { $parent.saveTypeDocument(IdTypeDocument); $('.alerta-form2').hide();}" data-toggle="modal" data-target="#modalDocumento">
ADICIONAR
</a>
</td>
</tr>
<!-- ko foreach: DocumentsArray() -->
<tr>
<td><i class="fa fa-file-text-o" aria-hidden="true"></i> Inclusão: <span data-bind="text: NewDate"></span></td>
<td>
<i class="fa fa-times pointer" data-toggle="modal" data-target="#modal-confirmation" aria-hidden="true" data-bind="visible : !frombase(),
, click: function(){ #*if (confirm('Deseja realmente deletar o documento?')) {*# $parent.savePath(Path); #*}*# }"></i>
</td>
</tr>
<!-- /ko-->
</tbody>
</table>
</div>
</div>
<div class="alert-button">
</div>
</form>
</div>
I forgot to mention that i have another javascript file that bindings the div document with a different model.
Press the F12 and check for any knockout js init (ko.applyBindings) error.
If there is any, fix it and try.
If no error exist, then make sure you have set a value to the model.Name() property by debugging the code.
and check your partial view and see whether you have narrow down the scope/ binding context to another complex property of you model which also has the Name property.
It would be better if you could give more info about partial view binding declaration and the how you are setting / loading the initial values to your model.
After looking for the solution and talk with some friends i found out what was the problem. I was binding the major div, that had the div id "documentos", and another information, and this was the problem.
I remove the binding of dvUserData, and put the binding in all the div that i had, including creating a new div just for the button.
This is how my div "documentos" is now.
<div class="tab-pane fade" id="documentos" role="tabpanel" aria-labelledby="documentos-tab">
#Html.Partial("Documentos")
<div class="alert-button mb-3">
<div id="dvDocumentValidate">
<button type="submit" class="btn btn-primary botao-vert" data-bind="click: editData">SALVAR</button>
</div>
</div>
</div>
And my bindings
ko.applyBindings(model, document.getElementById("dvLoading"));
ko.applyBindings(model, document.getElementById("personaldata"));
ko.applyBindings(model, document.getElementById("address"));
ko.applyBindings(model, document.getElementById("databank"));
ko.applyBindings(model, document.getElementById("dvDocumentValidate"));
ko.applyBindings(model, document.getElementById("corporatedata"));
I am getting into some angular development and I am building a very simple example, but somehow I am stuck... (Yes, yes I know angular 5 is out and I should't be doing it with angularjs, but I am just interested to compare the different approaches)
So my application has a simple Car object with an id, name and category.
The categories are exactly 3 and based on them I am showing 3 tabs and based on the currently selected tab, I add a car to this particular category.
Here is a screenshot:
So while the adding and removal work fine, the displaying/filtering of cars based on the category doesn't and I am not sure what is the right approach here.
My goal is that when I click on a 'tab', then I filter only the cars from that category.
This is part of my simple controller:
function CarController($scope, id, CarService) {
$scope.allCars = [];
$scope.name = '';
$scope.currentCategory = 'Sport';
$scope.categories = ['Sport', 'Luxury', 'Normal'];
$scope.addCar = addCar;
$scope.deleteCar = deleteCar;
$scope.setCurrentCategoryItem = function (item) {
$scope.currentCategory = item;
};
function addCar() {
CarService.addCar($scope.name, $scope.currentCategory);
$scope.name = '';
}
Here I have a simple function that is responsible for persisting the data:
function addCar(name, category, callback) {
callback = callback || angular.noop;
var Car = ResourceService.getResource(url, id);
var newCar = new Car();
newCar.name = name;
newCar.category = category;
newCar.$save(callback);
}
And here is my html template:
<div class="row">
<div class="col-xs-12">
<h1>Cars</h1>
</div>
<div class="tabbable tabs-below">
<ul class="nav nav-tabs">
<li ng-repeat="category in categories" ng-class="{active: category == currentCategory}">
{{category}}
</li>
</ul>
<div id="{{currentCategory}}" class="tab-content">
<hr/>
<div class="tab-pane active" role="tabpanel">
<div class="row">
<div class="col-xs-12">
<form ng-submit="addCar()" novalidate name="form">
<div class="alert alert-danger" ng-show="form.name.$error.notIn">
No duplicates allowed!
</div>
<div class="row">
<div class="col-xs-9">
<fieldset class="form-group">
<input type="text" class="form-control" placeholder={{currentCategory}}
ng-model="name" required name="name"
not-in="allCars"/>
</fieldset>
</div>
<div class="col-xs-3">
<button class="btn btn-success btn-block" type="submit"
data-description="submitLink"
ng-disabled="form.name.$pristine|| form.name.$error.required || form.name.$error.notIn">
Add
</button>
</div>
</div>
</form>
</div>
</div>
<table class="table table-striped">
<tr data-ng-repeat="car in allCars">
<td>{{car.name}}</td>
<td class="text-right">
<button class="btn btn-danger" ng-click="deleteItem(car)">
<span class="glyphicon glyphicon-remove"></span>
</button>
</td>
</tr>
</table>
</div>
</div>
</div>
<tr data-ng-repeat="car in allCars | filter: category">
<td>{{car.name}}</td>
<td class="text-right">
<button class="btn btn-danger" ng-click="deleteItem(car)">
<span class="glyphicon glyphicon-remove"></span>
</button>
</td>
</tr>
Use the $filter filter it is automatically used when angular parses the text in an ng-repeat (or anywhere you're passing a string or array really and angular is parsing it).
Example above just filters any fields for the value supplied, the below example specifies some property called "category" for the currentCategory (on scope) value.
<tr data-ng-repeat="car in allCars | filter: {category: currentCategory}">
<td>{{car.name}}</td>
<td class="text-right">
<button class="btn btn-danger" ng-click="deleteItem(car)">
<span class="glyphicon glyphicon-remove"></span>
</button>
</td>
</tr>
My Question:
I have a main page some fields when user click save button using Ajax.BeginForm i'm saving the details this is working successsfuly.
Inside main form there is one button(task) when user click that button partial window will open then they will fill some details. when partial window save button clicking automatically main page save action method is calling...first it save partial save details then immediately its saving main page details also then i'm getting two time saved successfully message.
when main page save button click only it should save main page fields. when partial page save button click it should save partial page fields only(partial page save i'm using jquery.
Main Page:
#using (Ajax.BeginForm("savePhase", "Search", new AjaxOptions() { HttpMethod = "POST", UpdateTargetId = "ChmHeaderPage",OnSuccess= "OnSuccessMain" }, new { enctype = "multipart/form-data" }))
{
#Html.HiddenFor(model => model.ChangeRequestList.FirstOrDefault().changeId);
#Html.HiddenFor(model => model.ChangeRequestList.FirstOrDefault().Phase);
<div class="col-md-offset-0 panel-body">
<div class="form-group">
#Html.LabelFor(model => model.Importance, htmlAttributes: new { #class = "col-md-3 control-label" })
<div class="col-md-3">
#Html.DropDownListFor(model => model.ImportanceVal, new SelectList(Model.Importance, "OptionId", "OptionName", Model.ImportanceVal), new { #class = "form-control", #Title = "Message Need to be Show" })
</div>
#Html.LabelFor(model => model.Urgency, htmlAttributes: new { #class = "col-md-2 control-label" })
<div class="col-md-3">
#Html.DropDownListFor(model => model.UrgencyVal, new SelectList(Model.Urgency, "OptionId", "OptionName", Model.UrgencyVal), new { #class = "form-control", #Title = "Message Need to be Show" })
</div>
</div>
<div class="col-md-12 ">
#Html.Label("Enter Task*")
<button type="button" id="Analysisbtn" class="btn btn-link " data-toggle="modal" data-target="#myModal">Select Task</button>
<!-- Modal -->
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-open strech-modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Analysis</h4>
</div>
<div class="modal-body">
#Html.Partial("_TaskPage")
</div>
</div>
</div>
</div>
</div>
<!-- Form actions -->
<div class="row panel-body">
<div class="col-md-12 text-center">
<button type="submit" name="buttonValue" class="btn btn-danger" value="Close">Save & Close</button>
<button type="submit" name="buttonValue" class="btn btn-primary" value="Save">Save</button>
</div>
</div>
</div>
}
Partial Page:
#model www.ChangeManagementTool.ViewModels.SearchViewModel
<div class="panel-group" id="accordion" role="tablist" aria-
multiselectable="true">
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="headingOne">
<h4 class="panel-title">
<a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
<i class="more-less glyphicon glyphicon-plus"></i>
Task
</a>
</h4>
</div>
<div id="collapseOne" class="panel-collapse collapse first" role="tabpanel" aria-labelledby="headingOne">
<div class="panel-body">
<div class="table-responsive center-block" data-tab-content="#item.Key" style="display:#displayText">
<table class="table table-responsive sena" id=#item.Key>
<tr>
<th>Department</th>
<th>Plant</th>
<th>Country</th>
<th>Responsibles</th>
<th>DueDate</th>
</tr>
<tbody>
#foreach (var analysisTask in item.Value)
{
<tr>
<td>
--DisplayFor code
</td>
<td>
--DisplayFor code
</td>
<td>
--DisplayFor code
</td>
<td>
--DisplayFor code
</td>
<td>
--DisplayFor code
</td>
</tr>
}
</tbody>
</table>
</div>
}
<div class="form-group">
<div class="col-md-12 text-center">
<button type="submit" id="btnSaveReal" class="btn btn-primary ">Save Task </button>
</div>
</div>
}
</div>
</div>
</div>
jquery Save Coding
<script type="text/javascript">
$('#btnSaveReal').click(function (e) {
var listex = [];
debugger;
$('#RealTask tbody tr').each(function (index, ele) {
var saveItem2 = {
ChangeId: $('#ChangeIdR').val(),
PlantId: $('#PlantIdR' + index).val(),
DepartmentId: $('#DepartmentIdR' + index).val(),
MstTaskId: $('#MstTaskIdR' + index).val(),
AffectedItemId: $('#AffectedItemIdR' + index).is(":checked")
}
listex.push(saveItem2);
})
//Save Coding
var url = applicationRoot + '/Search/SaveRealizationTaskdetails';
$.ajax({
url: url,
type: "POST",
data: JSON.stringify({ 'objmodelRel': listex, actionR: 'AnalyzeRealize' }),
dataType: "json",
traditional: true,
contentType: "application/json; charset=utf-8",
success: function (Data) {
if (Data.status) {
alert(Data.responseText);
} else {
alert(Data.responseText);
}
},
error: function () {
alert("An error has occured!!!");
}
});
});
function toggleIcon(e) {
$(e.target)
.prev('.panel-heading')
.find(".more-less")
.toggleClass('glyphicon-plus glyphicon-minus');
}
$('.panel-group').on('hidden.bs.collapse', toggleIcon);
$('.panel-group').on('shown.bs.collapse', toggleIcon);
Controller Code:
public ActionResult savePhase(SearchViewModel objmodel, string buttonValue)
{
save code---------------
return RedirectToAction("FetchChgReqDetails");
}
public JsonResult SaveRealizationTaskdetails(List<ChangeRequestRealizationTask> objmodelRel, string actionR)
{
--save code
return new JsonResult { Data = new { status = true, responseText = "Successfuly saved!" }, JsonRequestBehavior= JsonRequestBehavior.AllowGet };
}
As per your questions i will suggest you to try below this if it helpful to you.
First change Partial view button type="button" instead of type="submit"
and on main form submit send all data including Partial view data using AJAX
I'm building a web app using django and jQuery and on one of the pages the $(document).com('click'... event fires very intermittently. I have a list of items in a checkout queue, and an option to delete each item. If I go from top to the bottom of the list, the click events mostly fire (but not always). If I start from the bottom, sometimes they fire, sometimes not. Some need 2 clicks, some need 6+ clicks before registering.
Onto the code. This is the html django generates from the template:
<div class="container">
<table id="cart" class="table table-hover table-condensed">
<thead>
<tr>
<th style="width:70%">Product</th>
<th style="width:10%" class="text-center">Seller</th>
<th style="width:10%">Price</th>
<th style="width:10%"></th>
</tr>
</thead>
<tbody>
<tr id="product-3653672818">
<td data-th="Product">
<div class="row">
<div class="col-sm-3 hidden-xs"><img src="xyz.com/img.jpg" style="width: 121px; height: 88px;"></div>
<div class="col-sm-9">
<h4 class="nomargin">Product Name</h4>
<p>Product Description</p>
</div>
</div>
</td>
<td data-th="Seller" class="text-center">ONLINE</td>
<td data-th="Price">3.00</td>
<td class="actions" data-th="">
<button class="btn btn-danger btn-sm"><i class="fa fa-trash-o DeleteItem" id="3653672818"></i></button>
</td>
</tr>
<tr id="product-3653492642">
<td data-th="Product">
<div class="row">
<div class="col-sm-3 hidden-xs"><img src="xyz.com/img.jpg" style="width: 121px; height: 88px;"></div>
<div class="col-sm-9">
<h4 class="nomargin">Product #2 Title</h4>
<p>Product #2 Description</p>
</div>
</div>
</td>
<td data-th="Seller" class="text-center">ONLINE</td>
<td data-th="Price">4.00</td>
<td class="actions" data-th="">
<button class="btn btn-danger btn-sm"><i class="fa fa-trash-o DeleteItem" id="3653492642"></i></button>
</td>
</tr>
</div>
And this is my jQuery:
$(document).on('click','.DeleteItem',function(event){
event.preventDefault();
var thisID = $(this).attr("id");
var data = { Action: "delete", itemid: thisID};
var pr = "#product-"+thisID;
$(pr).fadeOut(500, function() { $(pr).remove(); });
$.ajax({
url: "/cart/",
type: "POST",
data: data,
beforeSend: function (xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
},
// handle a successful response
success: function (json) {
if (json.result == "OK") {
console.log(json);
console.log("success");
} else {
console.log(json);
console.log("failure");
}
},
// handle a non-successful response
error: function (xhr, errmsg, err) {
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
});
Ok, Just in case anybody else encounters this situation, I eventually worked out what was going on here.
The way I defined the button in the template was the culprit:
<button class="btn btn-danger btn-sm"><i class="fa fa-trash-o DeleteItem" id="3653672818"></i></button>
My jQuery was firing on $(document).on('click','.DeleteItem' which was a class defined in the "i" html element, rather than the main button class. The "fa-trash-o" class is a small trash can icon which only takes up about 1/3 of the button area.
So what would happen is if you clicked smack bang in the middle of the button (directly on the trash can), everything would work. But if you clicked elsewhere on the button, nothing happened. ie. Sometimes it works, sometimes it doesn't.
The fix was to move the "DeleteItem" class definition to the button:
<button class="btn btn-danger btn-sm DeleteItem" id="3653672818"><i class="fa fa-trash-o" ></i></button>