How do you isolate changes in React Props/State - mongodb

Within the context of Meteor/React I have a table component that subscribes to a Mongo Database, this subscription has a limit parameter that can be updated via props. I'm not sure why but it appears that the componentDidMount Lifecycle function is firing almost continually leading to unpleasant flickering.
The code is quite lengthy but I've attached what I think is the problematic section - more generally, how do you go about isolating what change in state/props is leading to a re-render? I've tried monitoring Chrome Tools but see no change there.
Any feedback or help appreciated!
import React from 'react';
import booksSingleLine from '../booksTable/booksSingleLine';
import TrackerReact from 'meteor/ultimatejs:tracker-react';
export default class booksListingTable extends TrackerReact(React.Component) {
constructor(props) {
super(props);
console.log("Constructor props are" + this.props.LimitProp);
}
componentWillMount() {
console.log("Mounting booksListingTable");
console.log("Will mount props are" + this.props.LimitProp);
this.state = {
}
}
componentDidMount(props){
// console.log("Did mount and props are" +props.LimitProp);
var limit = this.props.LimitProp
limit = parseInt(limit) || 5;
this.state = {
subscription: {
booksData: Meteor.subscribe("allbooks",{sort: {_id:-1}, limit: limit})
}
}
}
componentWillReceiveProps(props) {
console.log("component will get new props " + props.LimitProp);
// Note that for this lifecycle function we have to reference the props not this.props
// console.log("component will get weird props " + this.props.LimitProp);
var limit = props.LimitProp
limit = parseInt(limit) || 5;
this.state = {
subscription: {
booksData: Meteor.subscribe("allbooks", {limit: limit})
}
}
}
componentWillUnmount() {
}
booksDataLoad(){
var filteredCity = this.props.FilterProp;
console.log("filter is " + filteredCity);
if (filteredCity) {
console.log("just passing a few things")
return (
remotebookss.find({location: filteredCity}).fetch()
)
}
else {
console.log("passing everything to table");
return(
remotebookss.find().fetch()
)}}
render() {
return(
<div>
<table className="ui celled table">
<thead>
<tr>
<th onClick ={this.props.HeaderOnClick}>Name</th>
<th>Date</th>
<th>Summary</th>
<th>Site address</th>
<th>Price is</th>
</tr></thead>
<tbody>
{this.booksDataLoad().map( (booksData)=> {
return <booksSingleLine key={booksData._id} booksData={booksData} />
})}
</tbody>
<tfoot>
<tr><th colspan="3">
<div class="ui right floated pagination menu">
<a class="icon item">
<i class="left chevron icon"></i>
</a>
<a class="item" onClick= {this.props.methodLoadMore}>Load More</a>
<a class="icon item">
<i class="right chevron icon"></i>
</a>
</div>
</th>
</tr></tfoot>
</table>
</div>
)
}
}

I would strongly recommend you read the following blog post --
https://www.discovermeteor.com/blog/data-loading-react/
Things I see:
You're resetting state all over the place
You're not managing the subscription as a clear object - your code leaks them (FYI).
Here's a version that uses props and default props to setup your Limit, with that it checks only on startup and change to change the subscription.
import React from 'react';
import booksSingleLine from '../booksTable/booksSingleLine';
import TrackerReact from 'meteor/ultimatejs:tracker-react';
export default class booksListingTable extends TrackerReact(React.Component) {
static propTypes = {
LimitProp: React.PropTypes.number,
}
static defaultProps = {
LimitProp: 5,
}
constructor() {
super();
console.log("Constructor props are" + this.props.LimitProp);
const subscription = Meteor.subscribe("allbooks",{sort: {_id:-1}, limit: this.props.LimitProp})
this.state = {
booksData: subscription,
}
}
componentWillReceiveProps(nextProps) {
console.log("component will get new props " + nextProps.LimitProp);
// Start new subscription - if it's changed
if (this.props.LimitProp != nextProps.limitProp) {
// Stop old subscription
this.state.booksData.stop()
// Setup new subscription
const subscription = Meteor.subscribe("allbooks",{sort: {_id:-1}, limit: nextProps.LimitProp})
this.setState({ booksData: subscription })
}
}
componentWillUnmount() {
// Stop old subscription
this.state.booksData.stop()
}
booksDataLoad(){
var filteredCity = this.props.FilterProp;
console.log("filter is " + filteredCity);
if (filteredCity) {
console.log("just passing a few things")
return (
remotebookss.find({location: filteredCity}).fetch()
)
}
else {
console.log("passing everything to table");
return(
remotebookss.find().fetch()
)
}
}
render() {
return(
<div>
<table className="ui celled table">
<thead>
<tr>
<th onClick ={this.props.HeaderOnClick}>Name</th>
<th>Date</th>
<th>Summary</th>
<th>Site address</th>
<th>Price is</th>
</tr></thead>
<tbody>
{this.booksDataLoad().map( (booksData)=> {
return <booksSingleLine key={booksData._id} booksData={booksData} />
})
}
</tbody>
<tfoot>
<tr><th colspan="3">
<div class="ui right floated pagination menu">
<a class="icon item">
<i class="left chevron icon"></i>
</a>
<a class="item" onClick= {this.props.methodLoadMore}>Load More</a>
<a class="icon item">
<i class="right chevron icon"></i>
</a>
</div>
</th>
</tr></tfoot>
</table>
</div>
)
}
}

Related

How to add "handleRemove" function to Graphql both Query and Delete Mutation?

My Application is using React, Apollo client 2, Apollo Server and MongoDB as the database.
I try to add "handleRemove" function to query page that I use React.
But when I click "Delete" button, I get "deleteCustomer" is not the function.
Here is my code of this page, please help to find out the solution.
import React, { Component } from 'react';
import gql from 'graphql-tag';
import { graphql, compose } from 'react-apollo';
import { Link } from 'react-router-dom';
import { Button, Alert } from 'react-bootstrap';
import Loading from '../components/Loading';
class Customers extends Component {
handleRemove = async (customerID) => {
const result = await this.props.deleteCustomer({
variables: {
_id: customerID,
},
})
}
render() {
const { data: {loading, CustomersList }, match, history } = this.props;
return ( !loading ? (
<div className="Customers">
<h2><p className="text-center">Customer List</p></h2>
<Button><Link to={`/customers/new`}>Add Customer</Link></Button>
<br />
<br />
{CustomersList.length ?
<table className="zui-table zui-table-rounded">
<thead>
<tr>
<th><p className="text-center">List</p></th>
<th>
</th>
<th><p className="text-center">Salution</p></th>
<th><p className="text-center">Firstname</p></th>
<th><p className="text-center">Lastname</p></th>
<th><p className="text-center">Nickname</p></th>
<th><p className="text-center">Email</p></th>
<th><p className="text-center">Phone</p></th>
<th><p className="text-center">Mobile</p></th>
<th />
<th />
</tr>
</thead>
<tbody>
{CustomersList.map(({ _id, salution, firstname, lastname, nickname, email, phone, mobile, total_spent, createdAt, updatedAt }, index) => (
<tr key={_id}>
<td>{index+1}</td>
<td>
</td>
<td>{salution}</td>
<td>{firstname}</td>
<td>{lastname}</td>
<td>{nickname}</td>
<td>{email}</td>
<td>{phone}</td>
<td>{mobile}</td>
<td>
<p className="text-center">
<button className="btn btn-info btn-sm"
onClick={() => history.push(`${match.url}/${_id}/edit`)}
>Edit</button>
</p>
</td>
<td>
<p className="text-center">
<button className="btn btn-danger btn-sm"
onClick={() => this.handleRemove(_id)}
>Delete</button>
</p>
</td>
</tr>
))}
</tbody>
</table> : <Alert bsStyle="warning">Nobody registered yet!</Alert>}
</div>
) : <Loading /> );
}
}
export const customersListQuery = gql`
query customersListQuery {
CustomersList {
_id
salution
firstname
lastname
nickname
email
phone
mobile
total_spent
createdAt
updatedAt
}
}
`;
export const deleteCustomer = gql`
mutation deleteCustomer($_id: ID!) {
deleteCustomer(_id: $_id) {
_id
}
}
`;
export default compose(
graphql(customersListQuery),
graphql(deleteCustomer, { name: deleteCustomer }),
)(Customers);
The name of the mutation should be a string. The quotes are missing:
...
export default compose(
graphql(customersListQuery),
graphql(deleteCustomer, { name: "deleteCustomer" }),
)(Customers);

Send JSON data to server from react without rerender the page

I'm a bit new to ReactJS,
I've created a simple form and table, each time I hit the submit the state of the table change with the new data.
I'm using tornado as a backend server and mongodb as my DB.
I'm looking for a way to send the same JSON to the server on a second pipe (without rerendering the page again.)
How can I do it?
---- edit - react component -----
import Re
act from 'react';
export default class Reblaze_Dashboard extends React.Component {
constructor(props) {
super(props);
this.onNewUser = this.onNewUser.bind(this);
this.state = {
data: window.obj,
};
}
onNewUser(e) {
e.preventDefault();
const formData = {};
for (const field in this.refs) {
formData[field] = this.refs[field].value;
}
this.state.data.push(formData);
this.setState({
data: this.state.data,
});
}
render() {
return(
<div>
<h2>Dashboard page</h2>
<form onSubmit={this.onNewUser}>
<div className="form-group">
<label htmlFor="first-name-input">First name:</label>
<input type="text" className="form-control" ref="firstname" id="first-name-input" />
</div>
<div className="form-group">
<label htmlFor="last-name-input">Last name:</label>
<input type="text" className="form-control" ref="lastname" id="last-name-input" />
</div>
<input type="submit" value="Submit" className="btn btn-primary pull-right" />
</form>
<br /><br />
<div className="table-responsive">
<table className="table table-striped table-hover">
<thead>
<tr>
<td><h4>First name</h4></td>
<td><h4>Last name</h4></td>
</tr>
</thead>
<tbody>
{this.state.data.map((line, key) =>
<tr key={key}>
<td>{line.firstname}</td>
<td>{line.lastname}</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
)
}
}
You're submitting form data and immediately updating table without checking if your data reaches the server. This way it is possible to update user view while failing to update the database.
I strongly recommend to use some promise-based HTTP-client like Axios (https://github.com/mzabriskie/axios). Send some request, then wait for the promise resolve, and only after that update your component state.
You need something like this:
import React from 'react';
import axios from 'axios';
/*...*/
onNewUser(e) {
e.preventDefault();
const formData = {};
for (const field in this.refs) {
formData[field] = this.refs[field].value;
}
axios.post('yourApiUrl', formData)
// if request is sent and status is ok, update form and send second request
.then((res) => {
this.state.data.push(formData);
this.setState({
data: this.state.data,
});
return axios.post('yourApiUrl', formData);
})
// if second request is ok, receive a notification
.then((res) => {
console.log('second request is ok');
})
// if there is an error, receive a notification
.catch((err) => {
console.log(err);
})
}
/*...*/

How can I re-render the page after post request with react/redux?

There is a short time between the posting and the response from the server. How is it possible to cause your component to re-render when you get your positive response? I tried componentWillGetProps(){} and if-statements like
if(this.props.incomingItems){return: this.props.incomingItems}
but it none of them worked out. How did you solve this problem?
PS I'm using redux and axios for the requests.
import React, { Component } from 'react';
import { reduxForm } from 'redux-form';
import * as actions from '../../actions';
class eventView extends Component {
componentWillMount() {
this.props.eventView(this.props.params.eventID);
}
createNewRole(roleName){
this.props.createNewRole(roleName, this.props.params.eventID);
};
renderUsers(){
return this.props.eventDetails.userList.map((user)=>{
return(
<li className='list-group-item eventUserList' background-color="#f2f2f2" key={user._id}>
{user.userName}
</li>
);
});
};
deleteListItem(key){
const newKey = key.dispatchMarker.substr(44, 24);
this.props.RemoveRoleFromList(newKey)
this.props.fetchEvents();
}
renderRoles(){
return this.props.eventDetails.role.map((role)=>{
return(
<li className='list-group-item roleList' key={role._id}>
{role.roleName}
<img className="deleteListItem"
src="/img/trash.png"
key={role._id}
onClick={this.deleteListItem.bind(this)}/>
</li>
);
});
};
render() {
const { handleSubmit, fields: {eventName,location, eventPassword, roleName} } = this.props;
if(this.props.roleList){
console.log(this.props.roleList)
}
if (this.props.eventDetails){
return (
<div className='container-fluid'>
<div className="roleBox">
<form onSubmit={handleSubmit(this.createNewRole.bind(this))}>
<div>
<input {...roleName}
className="form-control roleBoxInputBar"
autoComplete="off"/>
<button className="RoleButton">Save</button>
</div>
<div className="listOfRoles">
<ul className="listOfRoles pre-scrollable">
{this.renderRoles()}
</ul>
</div>
</form>
</div>
<div>
<div>
<h1 className="eventName">
{this.props.eventDetails.eventName}
</h1>
</div>
<br/>
<table>
<tbody>
<tr>
<td className="eventViewTableLocation">Location:</td>
<td className="eventViewTable">{this.props.eventDetails.location}</td>
</tr>
<tr>
<td className="eventViewTableLocation">Date:</td>
<td className="eventViewTable">12/Feb/2018</td>
</tr>
<tr>
<td className="eventViewTableLocation">Time Left:</td>
<td className="eventViewTable">2 Days 2 Hours</td>
</tr>
</tbody>
</table>
</div>
<div className='eventViewUserBox'>
<h4 className="listOfUsers">Organisers:</h4>
<ul>
{this.renderUsers()}
</ul>
</div>
</div>
);
}else {
return (
<div>
</div>
);
}
}
}
function mapStateToProps(state) {
return { eventDetails: state.api.eventDetails };
return { roleList: state.api.roleList };
return { createdRole: state.api.createdRole };
}
export default reduxForm({
form: 'eventView',
fields: ['eventName', 'location', 'eventPassword', 'roleName']
}, mapStateToProps, actions)(eventView);
And my axios post goes something like this
export function createNewRole({roleName}, eventID){
return function(dispatch) {
axios.post(`${ROOT_URL}createRole/`+eventID, {roleName})
.then(response => {
if (response.data){
dispatch({
type: CREATED_ROLE,
payload: response.data,
});
};
})
.catch(response => dispatch(authError(response.data.error)));
};
};
Reducer:
export default function(state = {}, action) {
switch(action.type) {
case FETCH_ROLES:
return { ...state, roleList: action.payload };
case CREATED_ROLE:
return { ...state, createdRole: action.payload };
}
return state;
}
Thanks a lot!
function mapStateToProps(state) {
return { eventDetails: state.api.eventDetails };
return { roleList: state.api.roleList };
return { createdRole: state.api.createdRole };
}
This function always returns the first object. It should be:
function mapStateToProps(state) {
return {
eventDetails: state.api.eventDetails,
roleList: state.api.roleList,
createdRole: state.api.createdRole
};
}
I'm guessing roleList and createdRole are always undefined? Also it would be good if you would show the reducer.

Angular2 Modal Form - Displays data but I cant make edits

Good Morning,
I'm new to Angular and happily learning away.
I'm successfully loading form into my Modal on a "viewDetails" click.
However when I make a slight change to the Form from <form ngNoForm > to <form #editCashMovementForm="ngForm"> the data no longer loads.
I'm trying to make an editable pop-up form that updates on submit but its just this last step that I'm failing on.
Does anybody have advice please?
Thanks
Gws
Component.HTML
<div>
<table class="table table-hover">
<thead>
<tr>
<th><i class="fa fa-text-width fa-2x" aria-hidden="true"></i>Cash Movement ID</th>
<th><i class="fa fa-user fa-2x" aria-hidden="true"></i>PortfolioCode</th>
<th><i class="fa fa-paragraph fa-2x" aria-hidden="true"></i>CCY Out</th>
<th><i class="fa fa-map-marker fa-2x" aria-hidden="true"></i>Account Out</th>
<th><i class="fa fa-calendar-o fa-2x" aria-hidden="true"></i>Date</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let cashmovement of cashmovements">
<td> {{cashmovement.cashMovementId}}</td>
<td>{{cashmovement.portfolioCode}}</td>
<td>{{cashmovement.ccyo}}</td>
<td>{{cashmovement.accountO}}</td>
<td>{{cashmovement.date | dateFormat | date:'medium'}}</td>
<td><button class="btn btn-danger" (click)="removeCashMovement(cashmovement)"><i class="fa fa-trash" aria-hidden="true"></i>Delete</button></td>
<td><button class="btn btn-primary" (click)="viewCashMovementDetails(cashmovement.cashMovementId)"><i class="fa fa-info-circle" aria-hidden="true"></i>Edit</button></td>
</tr>
</tbody>
</table>
</div>
<div bsModal #childModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" *ngIf="selectedCashMovementLoaded">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" aria-label="Close" (click)="hideChildModal()"><span aria-hidden="true">×</span></button>
<h4>{{cashmovementDetails.cashMovementId}} Details</h4>
</div>
<div class="modal-body">
<form ngNoForm >
<!--<form #editCashMovementForm="ngForm" (ngSubmit)="updateCashMovement(editCashMovementForm)">-->
<div class="form-group">
<div class="row">
<div class="col-md-4">
<label class="control-label"><i class="fa fa-user" aria-hidden="true"></i>Portfolio Code</label>
<input type="text" class="form-control" [(ngModel)]="cashmovementDetails.portfolioCode" />
</div>
<div class="col-md-4">
<label class="control-label"><i class="fa fa-text-width" aria-hidden="true"></i>Currency Out</label>
<input type="text" class="form-control" [(ngModel)]="cashmovementDetails.ccyo" />
</div>
<div class="col-md-4">
<label class="control-label"><i class="fa fa-paragraph" aria-hidden="true"></i>Account Out</label>
<input type="text" class="form-control" [(ngModel)]="cashmovementDetails.accountO" />
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-xs-6">
<label class="control-label"><i class="fa fa-calendar-o" aria-hidden="true"></i>Date</label>
<input type="text" class="form-control" [(ngModel)]="cashmovementDetails.date" />
</div>
</div>
</div>
<hr/>
<button type="button" [disabled]="!editCashMovementForm.form.valid" class="btn btn-default" (click)="updateCashMovement(editCashMovementForm)"><i class="fa fa-pencil-square-o" aria-hidden="true"></i>Update</button>
</form>
</div>
</div>
</div>
</div>
Component.ts
import { Component, OnInit, ViewChild, Input, Output, trigger, state, style, animate, transition } from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { NgForm } from '#angular/forms';
import { ModalDirective } from 'ng2-bootstrap';
import { CashMovementDataService } from './cashmovement.data.service';
import { DateFormatPipe } from '../shared/pipes/date-format.pipe';
import { ItemsService } from '../shared/utils/items.service';
import { NotificationService } from '../shared/utils/notification.service';
import { ConfigService } from '../shared/utils/config.service';
import { MappingService } from '../shared/utils/mapping.service';
import { ICashMovement, Pagination, PaginatedResult } from '../shared/interfaces';
#Component({
moduleId: module.id,
selector: 'cashmovements',
templateUrl: './cashmovement-list.component.html'
})
export class CashMovementListComponent implements OnInit {
#ViewChild('childModal') public childModal: ModalDirective;
cashmovements: ICashMovement[];
// Modal properties
#ViewChild('modal')
modal: any;
items: string[] = ['item1', 'item2', 'item3'];
selected: string;
output: string;
selectedCashMovementId: number;
cashmovementDetails: ICashMovement;
selectedCashMovementLoaded: boolean = false;
index: number = 0;
backdropOptions = [true, false, 'static'];
animation: boolean = true;
keyboard: boolean = true;
backdrop: string | boolean = true;
constructor(private route: ActivatedRoute,
private router: Router,
private dataService: CashMovementDataService,
private itemsService: ItemsService,
private notificationService: NotificationService,
private configService: ConfigService,
private mappingService: MappingService) { }
ngOnInit() {
this.loadCashMovements();
}
loadCashMovements(){
this.dataService.getCashMovements()
.subscribe((cashmovements: ICashMovement[]) => {
this.cashmovements = cashmovements;
},
error => {
this.notificationService.printErrorMessage('Failed to load cashmovements. ' + error);
});
}
removeCashMovement(cashmovement: ICashMovement) {
this.notificationService.openConfirmationDialog('Are you sure you want to delete this cashmovement?',
() => {
this.dataService.deleteCashMovement(cashmovement.cashMovementId)
.subscribe(() => {
this.itemsService.removeItemFromArray<ICashMovement>(this.cashmovements, cashmovement);
this.notificationService.printSuccessMessage(cashmovement.cashMovementId + ' has been deleted.');
},
error => {
this.notificationService.printErrorMessage('Failed to delete ' + cashmovement.cashMovementId + ' ' + error);
});
});
}
viewCashMovementDetails(id: number) {
this.selectedCashMovementId = id;
this.dataService.getCashMovement(this.selectedCashMovementId)
.subscribe((cashmovement: ICashMovement) => {
this.cashmovementDetails = this.itemsService.getSerialized<ICashMovement>(cashmovement);
this.cashmovementDetails.date = new DateFormatPipe().transform(cashmovement.date, ['local']);
this.selectedCashMovementLoaded = true;
this.childModal.show();
},
error => {
this.notificationService.printErrorMessage('Failed to load cashmovement. ' + error);
});
}
updateCashMovement(editCashMovementForm: NgForm) {
var scheduleMapped = this.mappingService.mapCashMovementDetailsToCashMovement(this.cashmovementDetails);
this.dataService.updateCashMovement(scheduleMapped)
.subscribe(() => {
this.notificationService.printSuccessMessage('Cash Movement has been updated');
},
error => {
this.notificationService.printErrorMessage('Failed to update cash movement. ' + error);
});
}
public hideChildModal(): void {
this.childModal.hide();
}
}
data.service.ts
import { Injectable } from '#angular/core';
import { Http, Response, Headers } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import {Observer} from 'rxjs/Observer';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { ICashMovement, ICashMovementDetails, Pagination, PaginatedResult } from '../shared/interfaces';
import { ItemsService } from '../shared/utils/items.service';
import { ConfigService } from '../shared/utils/config.service';
#Injectable()
export class CashMovementDataService {
_baseUrl: string = '';
constructor(private http: Http,
private itemsService: ItemsService,
private configService: ConfigService) {
this._baseUrl = configService.getApiURI();
}
getCashMovements(): Observable<void> {
return this.http.get(this._baseUrl + 'cashmovements')
.map((res: Response) => { return res.json(); })
.catch(this.handleError);
}
deleteCashMovement(id: number): Observable<void> {
return this.http.delete(this._baseUrl + 'cashmovements/?id=' + id)
.map((res: Response) => {
return;
})
.catch(this.handleError);
}
getCashMovement(id: number): Observable<ICashMovement> {
return this.http.get(this._baseUrl + 'cashmovements/?id=' + id)
.map((res: Response) => {
return res.json();
})
.catch(this.handleError);
}
updateCashMovement(cashmovement: ICashMovement): Observable<void> {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.put(this._baseUrl + 'cashmovements/?id=' + cashmovement.cashMovementId, JSON.stringify(cashmovement), {
headers: headers
})
.map((res: Response) => {
return;
})
.catch(this.handleError);
}
private handleError(error: any) {
var applicationError = error.headers.get('Application-Error');
var serverError = error.json();
var modelStateErrors: string = '';
if (!serverError.type) {
console.log(serverError);
for (var key in serverError) {
if (serverError[key])
modelStateErrors += serverError[key] + '\n';
}
}
modelStateErrors = modelStateErrors = '' ? null : modelStateErrors;
return Observable.throw(applicationError || modelStateErrors || 'Server error');
}
}
I need to change my form inputs from
<input type="text" class="form-control" [(ngModel)]="cashmovementDetails.portfolioCode" />
To
<input type="text" class="form-control" [(ngModel)]="cashmovementDetails.portfolioCode" name="portfolioCode" #portfolioCode="ngModel"/>

Update partialview after Model updaton using Model popup

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