I am using datatables and jquery dialog. Overall I have 3 forms and 3 datatables.
My script is working great but the thing I am struggling with is updating the correct datatable on success of ajax save (It doesn't even have to be the correct corresponding table, it could update all 3 tables on any of the 3 form saves.)
Any guidance would be greatly appreciated.
Page with buttons for showing datatable/forms in dialog
<div style="float:left;">
<button class="menubutton" id="view_academic">Academic</button>
<button class="menubutton" id="view_business">Business/Suppport</button>
<button class="menubutton" id="line_managers">Managers/Divisions</button>
<br/>
<br/>
</div>
<div style="float:right;">
Add Managers/Divisions
Add Academic
Add Business/Suppport
<br/>
<br/>
</div>
<div style="clear:both"></div>
<div id="academic_list">
<h2>Academic Entitlements</h2>
<table class="dataTable" id="academic_table" cellpadding="2" cellspacing="2" width="100%">
<thead>
<tr>
<th>Year</th>
<th>Employee</th>
<th>Division</th>
<th>Contract</th>
<th>Entitlement</th>
<th>Line Manager</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="4" class="dataTables_empty">Loading data from server</td>
</tr>
</tbody>
</table>
</div>
<div id="business_list" class="the_options" style="display:none;">
<h2>Business & Manual Entitlements</h2>
<table class="dataTable" id="business_table" cellpadding="2" cellspacing="2" width="100%">
<thead>
<tr>
<th>Year</th>
<th>Employee</th>
<th>FT/PT</th>
<th>Weekly Hours</th>
<th>Division</th>
<th>Commencement</th>
<th>Entitlement</th>
<th>Line Manager</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="4" class="dataTables_empty">Loading data from server</td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="line_managers_list" class="the_options" style="display:none;">
<h2>Line Managers & Divisions</h2>
<table class="dataTable" id="line_managers_table" cellpadding="2" cellspacing="2" width="100%">
<thead>
<tr>
<th>Division</th>
<th>Name</th>
<th>Line Manager</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="4" class="dataTables_empty">Loading data from server</td>
</tr>
</tbody>
</table>
</div>
initialise Datatables
$(function() {
// Implements the dataTables plugin on the HTML table
var $acTable= $("#academic_table").dataTable( {
"oLanguage": {
"sSearch": "Filter:"
},
"bProcessing": true,
"bServerSide": true,
"sAjaxSource": "scripts/academic_serverside.php",
"iDisplayLength": 10,
"bJQueryUI": false,
"sPaginationType": "scrolling",
"sDom": '<"top"iflp<"clear">>rt>',
"sScrollX": "100%",
"sScrollXInner": "100%",
"bScrollCollapse": true
});
});
$(function() {
// Implements the dataTables plugin on the HTML table
var $buTable= $("#business_table").dataTable( {
"oLanguage": {
"sSearch": "Filter:"
},
"bProcessing": true,
"bServerSide": true,
"sAjaxSource": "scripts/business_serverside.php",
"iDisplayLength": 10,
"bJQueryUI": false,
"sPaginationType": "scrolling",
"sDom": '<"top"iflp<"clear">>rt>',
"sScrollX": "100%",
"sScrollXInner": "100%",
"bScrollCollapse": true
});
});
$(function() {
// Implements the dataTables plugin on the HTML table
var $lmTable= $("#line_managers_table").dataTable( {
"oLanguage": {
"sSearch": "Filter:"
},
"bProcessing": true,
"bServerSide": true,
"sAjaxSource": "scripts/line_managers_serverside.php",
"iDisplayLength": 10,
"bJQueryUI": false,
"sPaginationType": "scrolling",
"sDom": '<"top"iflp<"clear">>rt>'
});
});
$(document).ready(function() {
$(".the_options").hide();
});
Dialogs/datatables show/hide/open/close and AJAX save form:
$(document).ready(dialogForms);
function dialogForms() {
$('a.menubutton').click(function() {
var a = $(this);
$.get(a.attr('href'),function(resp){
var dialog = $('<div>').attr('id','formDialog').html($(resp).find('form:first').parent('div').html());
$('body').append(dialog);
dialog.find(':submit').hide();
dialog.dialog({
title: a.attr('title') ? a.attr('title') : '',
modal: true,
buttons: {
'Save': function() {
submitFormWithAjax($(this).find('form'));
$(this).dialog('close');
$lmTable.fnDraw('');
},
'Cancel': function() {$(this).dialog('close');}
},
close: function() {$(this).remove();},
width: 600,
height: 500
});
}, 'html');
return false;
});
}
function submitFormWithAjax(form) {
form = $(form);
$.ajax({
url: form.attr('action'),
data: form.serialize(),
type: (form.attr('method')),
dataType: 'script',
success: function(data){
$(this).dialog('close');
$lmTable.fnDraw('');
}
});
return false;
}
$(function() {
$("#add_academic")
.button()
.click(function() {
$("#academic-form").dialog( "open" );
});
$("#add_line_managers")
.button()
.click(function() {
$("#line-managers-form").dialog( "open" );
});
$("#add_business")
.button()
.click(function() {
$("#business-form").dialog( "open" );
});
$("#view_academic")
.button()
.click(function() {
$('#academic_list').show();
$('#business_list').hide();
$('#line_managers_list').hide();
});
$("#view_business")
.button()
.click(function() {
$('#academic_list').hide();
$('#business_list').show();
$('#line_managers_list').hide();
});
$("#line_managers")
.button()
.click(function() {
$('#academic_list').hide();
$('#business_list').hide();
$('#line_managers_list').show();
});
});
To update a table simply call fnDraw() on it. Since you are not using global variables, you must retrieve the table first
var $lmTable = $("#line_managers_table").dataTable( { bRetrieve : true } );
$lmTable.fnDraw();
EDIT - to show only the right table you could do something like:
function dialogForms() {
$('a.menubutton').click(function() {
var id = this.id;// Save the id of the clicked button
var a = $(this);
$.get(a.attr('href'),function(resp){
var dialog = $('<div>').attr('id','formDialog').html($(resp).find('form:first').parent('div').html());
$('body').append(dialog);
dialog.find(':submit').hide();
dialog.dialog({
title: a.attr('title') ? a.attr('title') : '',
modal: true,
buttons: {
'Save': function() {
submitFormWithAjax($(this).find('form'), id);// Pass the id to the function
function submitFormWithAjax(form, id) {
form = $(form);
var table_id;
// Choose the table to display depending on the id, i made some guesses but adjust this
switch(id){
case 'view_academic': table_id = '#academic_table';
break;
case 'view_business': table_id = '#business_table';
break;
case 'line_managers': table_id = '#line_managers_list';
break;
}
$.ajax({
url: form.attr('action'),
data: form.serialize(),
type: (form.attr('method')),
dataType: 'script',
success: function(data){
$(this).dialog('close');
// Refresh table
var oTableToUpdate = $(table_id).dataTable( { bRetrieve : true } );
$oTableToUpdate .fnDraw();
// Hide all tables
$('table').hide();
// Show the refreshed
$(table_id).show();
}
});
return false;
}
Related
I have a vuejs project, where I have my parent component as ProductGroup.vue which has a child ProductGroupmodal.vue. The productGroup has list of records, upon clicking edit button on each row the modal (ProductGroupmodal.vue) should pop up with the input fields filled with the data. I have passed each row data as prop to the child component on clicking edit button. Then, I have assigned the prop data to the form object in the created() method of child component. But the form is not filled with previous records. Here is my code below:
This is Parent component.
<template>
<div class="tables-basic">
<h2 class="page-title">Product Group - <span class="fw-semi-bold">List</span></h2>
<b-button v-b-modal.modal1 #click.prevent="newModal()">Add New</b-button>
<b-row>
<b-col>
<div class="table-resposive">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th class="hidden-sm-down">Action</th>
</tr>
</thead>
<tbody>
<tr v-for="row in allData" :key="row.id">
<td>{{row.name}}</td>
<td>
<b-button v-b-modal.modal1 #click.prevent="editModal(row)">Edit</b-button>
</td>
</tr>
</tbody>
</table>
</div>
</b-col>
</b-row>
<ProductGroupModal :editValue="editValue" :editing='editing'
/>
</div>
</template>
<script>
import ProductGroupModal from '#/components/ProductGroup/ProductGroupModal.vue';
export default {
name: 'ProductGroup',
components: { ProductGroupModal },
data() {
return {
editValue:{},
editing: false,
allData:{},
};
},
methods: {
loadData() {
ProductGroupDataService.getAll()
.then(response => {
this.allData = response.data;
})
.catch(e => {
console.log(e);
});
},
newModal(){
this.editing=false;
},
editModal(row){
this.editValue = row;
this.editing = true;
},
},
mounted() {
this.loadData();
}
};
</script>
This is my Child component (ProductGroupModal.vue):
<template>
<b-modal ref="productGroupModal" id="modal1" centered v-bind:title="this.editing==true ? 'Update' : 'Add' "
#hidden="resetModal"
#ok.prevent="submitForm() ">
<v-form ref="productGroupForm" id="productGroupForm">
<v-text-field
v-model="form.name"
label="Name"
required
></v-text-field>
</v-form>
</b-modal>
</template>
<script>
import ProductGroupDataService from "#/services/ProductGroupDataService";
export default {
props: {
editValue: {
type: Object,
default: () => ({empty: true}),
},
editing: {
type: Boolean,
default: () => ({}),
}
},
name: 'productGroupModal',
data() {
return {
form: {
id: '',
name: '',
code: '',
},
};
},
methods:{
submitForm() {
var data = {
"name": this.form.name,
"code": this.form.code
};
},
created(){
if (!this.editValue.empty) {
this.form = this.editValue
console.log('edit:'+ this.editValue);
}
else{
console.log('falseedit:'+ this.editValue);
}
}
}
</script>
I think my b-modal(child component) is rendered before the data in the form is being set through prop .How can I solve it?Can anyone help me with this please!
I can't get enough info about your b-modal components.
but I think this maybe related to the props passed to child is async.
when created, the asyncprops editValue is not ready yet. so nothing is assigned to the form.
you can add v-if on the child component, render the child component only when data is ready:
<ProductGroupModal v-if="allData.length" :editValue="editValue" :editing='editing'
/>
do not write this.form = this.editValue in created hook;
computed: {
form() {
return this.editValue || {};
}
}
I want to filter the following in VueJs 2.
My Component is the following:
<template>
Search <input name="query" v-model="query" class="form-control">
<table class="table">
<thead>
<tr>
<th>User name</th>
<th>User email/th>
<th>Get logs</th>
</tr>
</thead>
<tbody v-for="user in filteredUsers">
<tr>
<td> {{ user.firstname }} </td>
<td> {{ user.lastname }} </td>
<td> <a v-on:click="getUserLogs(user.user_id)">Show</a> </td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import ConnectionService from '../../components/services/ConnectionService';
const connectionService = new ConnectionService();
export default {
data() {
return {
users: [],
query: '',
betweenDates: {
from: '',
to: ''
},
logs: {},
logsVisibility: false
}
},
created() {
this.getUsers();
},
computed: {
filteredUsers() {
return this.findBy(this.users, this.query, 'lastname')
}
},
methods: {
getUsers() {
this.$http.get(hostname + 'name=person_list&session_id=' + sessionApiId).then(response => {
this.users = connectionService.renderMultipleInstances(response.body);
}, response => {
// error callback
});
},
getUserLogs(id) {
let self = this;
axios.post('/logs/get_user_logs', {
userId: id,
}).then(function (response) {
self.logs = response.data;
self.logsVisibility = true;
console.log(response.data);
});
},
findBy(list, value, column) {
return list.filter(function (item) {
return item[column].includes(value)
})
}
}
}
</script>
I have the following data to filter through it:
users:Array[4095]
0:Object
firstname:"Анастасия"
id:206
lastname:"Никифорова"
middlename:"Юрьевна"
user_id:192
1:Object
firstname:null
id:3362
lastname:null
middlename:null
user_id:2046
...
And error is the following:
[Vue warn]: Error in render function: "TypeError: Cannot read property 'includes' of null"
In 1:Object lastname:null. It causes your error
You can add line before return
item[column] || (item[column] = '');
or
return list.filter(function (item) {
return (item[column] || '').includes(value)
})
I had a similar problem to fix it I replace every null value from my object with a ' ' (empty string)
I have a collection that handles default values for forms. I need to build a UI to update the default values themselves, instead of force updating via mongo backed.
I've used aldeed's update-each functionality. The data is being fetched from the DB and displayed in the table. However, when I try to update by inputting new values in the textbox, it does not persist. In fact, it keeps throwing this error which i'm not aware of.
Exception in template helper: TypeError: Cannot read property 'namedContext' of undefined
at Object.autoFormFieldIsInvalid
As a sample, here is what I'm working with:
Mongo Collection:
meteor:PRIMARY> db.testCollection.find()
{ "_id" : ObjectId("577ccd87f57f43d790c3ec49"), "schemaName" : "test_schema", "label" : "test_lable", "value" : "test_value" }
Schema:
test_schema = new SimpleSchema({
"schemaName": {
type: String,
},
"label": {
type: String,
},
"value": {
type: String,
}
});
testCollection.attachSchema(test_schema);
Template:
<template name = "testTemplate">
<table class="table table-bordered table-condensed">
<thead>
<tr>
<td style="width: 85px">Schema Name</td>
<td style="width: 85px">Label</td>
<td>Default Value</td>
<td style="width: 250px">New Default Value</td>
</tr>
</thead>
<tbody>
{{#each items}}
<tr>
<td>{{this.schemaName}}</td>
<td>{{this.label}}</td>
<td>{{this.value}}</td>
<td>
{{#autoForm id=updateDefaiultsID type="update" collection=testCollection doc=this autosave=true}}
{{> afFormGroup name="value" label=false}}
{{/autoForm}}
</td>
</tr>
{{/each}}
</tbody>
</table>
</template>
Helper
import { Template } from 'meteor/templating';
import '../templates/testTemplate.html';
if (Meteor.isServer) {
Meteor.publish(null, function () {
return testCollection.find();
});
testCollection.allow({
update: function () {
return true;
}
});
}
else if (Meteor.isClient) {
Template["testTemplate"].helpers({
items: function () {
return testCollection.find({}, {sort: {name: 1}});
},
updateDefaiultsID: function () {
return "testTemplate" + this._id;
}
});
}
Change this
from
<td>{{this.schemaName}}</td>
to
<td>{{this.schema_name}}</td>
I'm using ngTable with this code:
HTML:
<table data-ng-table="tableParams" class="table table-condensed table-bordered table-striped">
<tbody>
<tr data-ng-repeat="task in $data">
<td data-title="''">
<input type="checkbox" style="display: block; margin: auto;" ng-model="task.IsSelected" ng-change="optionToggled()">
</td>
<td data-title="''" style="text-align: center">
<i class="glyphicon glyphicon-flag" ng-show="task.IsToday"></i>
<i class="glyphicon glyphicon-ok" ng-show="task.IsCompleted"></i>
</td>
<td data-title="'Subject'" data-sortable="'Subject'">{{task.Subject}}</td>
<td data-title="'Priority'" data-sortable="'PriorityValue'">{{task.PriorityValue}}</td>
<td data-title="'Status'" data-sortable="'StatusValue'">{{task.StatusValue}}</td>
<td data-title="'Due Date'" data-sortable="'DueDate'">{{task.DueDate}}</td>
<td data-title="'Completed'" data-sortable="'CompletedValue'">{{task.CompletedValue}}</td>
<td data-title="'Date Completed'" data-sortable="'DateCompleted'">{{task.DateCompleted}}</td>
<td data-title="'Action'">
<button type="button" style="display: block; margin: auto;" class="btn btn-info btn-xs" ng-click="editRow(task)">
<i class="glyphicon glyphicon-edit"></i>
</button>
</td>
</tr>
</tbody>
</table>
Javascript:
$scope.tableData = [];
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 10, // count per page
sorting: { DueDate: "asc" } // initial sort order,
},
{
paginationMaxBlocks: 10,
paginationMinBlocks: 2,
getData: function($defer, params) {
var sorting = params.sorting();
var keySorting = Object.keys(sorting)[0];
var valueSorting = sorting[keySorting];
var count = params.count();
var pageIndex = params.page() - 1;
var keySearch = angular.isDefined($scope.textSearch) ? $scope.textSearch : '';
taskService.pagingTasks(pageIndex * count, count, keySearch, keySorting, valueSorting).then(function(data) {
var obj = angular.fromJson(data);
params.total(obj.Total);
formatToDateTime(obj.Data);
$scope.tableData = obj.Data;
$defer.resolve(obj.Data);
});
}
});
But when I run my website I see ngTable generate
And my browser console show this error:
I have no idea why ngTable can't generate columns header.
Currently, I must create columns header by manually.
I found my answer:
You can fix this issues base on this post :
AngularJS: 'Template for directive must have exactly one root element' when using 'th' tag in directive template
Modified these lines in file "ng-table.js" and remove tr tag in : "filterRow.html", "groupRow.html", "sorterRow.html".
(template)
$templateCache.put('ng-table/header.html', '<tr ng-if="params.hasGroup()" ng-show="$groupRow.show" class="ng-table-group-header" ng-table-group-row></tr> <tr class="ng-table-sort-header headerrow" ng-table-sorter-row></tr> <tr ng-show="show_filter" class="ng-table-filters" ng-table-filter-row></tr> ');
(directive)
function ngTableGroupRow(){
var directive = {
restrict: 'A',
//replace: true,
templateUrl: 'ng-table/groupRow.html',
scope: true,
controller: 'ngTableGroupRowController',
controllerAs: 'dctrl'
};
return directive;
}
function ngTableSorterRow(){
var directive = {
restrict: 'A',
//replace: true,
templateUrl: 'ng-table/sorterRow.html',
scope: true,
controller: 'ngTableSorterRowController'
};
return directive;
}
function ngTableFilterRow(){
var directive = {
restrict: 'A',
//replace: true,
templateUrl: 'ng-table/filterRow.html',
scope: true,
controller: 'ngTableFilterRowController'
};
return directive;
}
I have index page which contains 2 partial views.One for displaying Roles and another for displaying corresponding privileges.
#model IEnumerable<sample.Models.Role_Privilege_Map>
#{
ViewBag.Title = "RolePrivilgeMapping";
}
<h2>RolePrivilgeMapping</h2>
<script>
$(document).ready(function () {
registerTableClick();
//$("#tblRole tbody tr:first").trigger();
});
function registerTableClick() {
$("#tblRole tbody tr").on("click", function () {
$(this).siblings().removeClass('selected_row');
$(this).addClass("selected_row");
var roleId = parseInt($(this).find("td:eq(0)").text());
loadPrivilege(roleId);
});
function loadtrackPrivilege(roleId) {
$("#PrivilegeWrapper").load("#Url.Action("PrivilegesPartial", "RolePrivilegeMapping")",
{ 'roleID': roleId },
function (response, status, xhr) {
if (status == "error") {
alert("An error occurred while loading privileges.");
}
});
}
}
</script>
<div id="RolePrivilgeMappingWrapper">
<div class="float-left" id="roleWrapper">
#Html.Partial("_Role", sample.Models.DataProvider.DataProvider.GetRoleNames())
</div>
<div class="float-left" id="PrivilegeWrapper">
#Html.Partial("_Privilege", sample.Models.DataProvider.Provider.GetPrivilegeNames())
</div>
</div>
Here is my _Role.cshtml
#model IEnumerable<sample.Models.webpages_Roles>
#{
ViewBag.Title = "Index";
}
<script type="text/ecmascript">
$(document).ready(function () {
$.ajaxSetup({ cache: false });
$(".editDialog").live("click", function (e) {
var url = $(this).attr('href');
$("#dialog-edit").dialog({
title: 'Edit Role',
autoOpen: false,
resizable: false,
height: 255,
width: 400,
show: { effect: 'drop', direction: "up" },
modal: true,
draggable: true,
open: function (event, ui) {
$(this).load(url);
},
close: function (event, ui) {
$(this).dialog('close');
}
});
$("#dialog-edit").dialog('open');
return false;
});
});
</script>
<div class="settingsTable" style="position: relative; width: 100%; margin: 0 auto">
<div style="width: 50%; margin: 0 auto">
<div style="width: 50%; margin: 0 auto">
<h2>Role</h2>
</div>
</div>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table id="tblRole">
<tr>
<th>
#Html.DisplayNameFor(model => model.RoleId)
</th>
<th>
#Html.DisplayNameFor(model => model.RoleName)
</th>
<th>Action</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.RoleId)
</td>
<td>
#Html.DisplayFor(modelItem => item.RoleName)
</td>
<td>
#Html.ActionLink("Edit", "OpenEditRoleDialog", "RolePrivilegeMapping", new { id = item.RoleId }, new { #class="editDialog"}) |
#Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</table>
<div id="dialog-edit" style="display: none">
</div>
</div>
On Role partial view I have edit link for every row displayed.
here is my _editrole.cshtml
#model sample.Models.webpages_Roles
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Ajax.BeginForm("EditRole", "RolePrivilegeMapping", new AjaxOptions { HttpMethod = "POST" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>webpages_Roles</legend>
#Html.HiddenFor(model => model.RoleId)
<div class="editor-label">
#Html.LabelFor(model => model.RoleName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.RoleName)
#Html.ValidationMessageFor(model => model.RoleName)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
Now while I click on edit link a jquery modal box gets displayed for editing details.I submit the changes asychronously as
#using (Ajax.BeginForm("EditRole", "RolePrivilegeMapping", new AjaxOptions { HttpMethod = "POST" }))
And the edit method is
public ActionResult EditRole(webpages_Roles webpages_roles)
{
if (ModelState.IsValid)
{
db.Entry(webpages_roles).State = EntityState.Modified;
db.SaveChanges();
}
return View("index");
}
My problem is
1. The dialog box is not getting closed. I have to manually click the cross
bar.
2. The Role partial view is not getting updated until I have to refresh the page.
I followed this link http://www.mindstick.com/Articles/279bc324-5be3-4156-a9e9-dd91c971d462/CRUD%20operation%20using%20Modal%20dialog%20in%20ASP%20NET%20MVC#.VVlyBLmqpHx