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

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.

Related

dynamic props with teleport modal vuejs3

I have a view with a child component and props, on a tr click we display modal with different values, so the properties set is different following the TR tab clicked
<template>
<ModalOrderDetail :display="modal_display" :id_order="order_id"/>
<div>
<table class="table table-striped">
<thead class="table-dark">
<tr>
<th scope="col">ID</th>
</tr>
</thead>
<tbody>
<tr
v-for="order in result.orders"
:key="order.id"
#click="
$emit('update:id_order', order.id)
showModal()
"
>
<th scope="row">{{ order.id }}</th>
</tr>
</tbody>
</table>
</div>
<script>
import ModalOrderDetail from '#/components/ModalOrderDetail.vue'
import OrderService from '#/services/OrderService.js'
export default {
components: {
ModalOrderDetail
},
props: {
id_order: {
type: Number,
required: true
}
},
data() {
return {
result: [],
customer: null,
modal_display: true,
order_id:null
}
},
methods: {
showModal() {
console.log(this.modal_display)
console.log(this.order_id)
}
},
created() {
OrderService.getOrders()
.then(response => {
this.result = response.data
console.debug(this.result.orders)
})
.catch(error => {
console.log(error)
})
}
}
and here the modal
<template>
<teleport v-if="display" to="#modals">
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
</div>
<div class="modal-body">
<p>Commande N°</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Save changes</button>
<button
type="button"
class="btn btn-secondary"
#click="display = !display"
>
Close
</button>
</div>
</div>
</div>
</div>
</teleport>
</template>
<script>
export default {
name: 'ModalOrderDetail',
props: {
display: {
type: Boolean,
required: true
},
id_order: {
type: Number,
required: true
}
},
methods: {
print() {
console.log(this.id_order)
console.log(this.display)
}
}
}
</script>
<style scoped>
.modal {
display: block;
position: absolute;
}
</style>
problem i have a mutation props error, i really don't know how to pass dynamic props to my modal and make it work properly ?
In modal component replace #click="display = !display" by emitting an event #click="$emit('close')"
and add close to emits option
export default {
name: 'ModalOrderDetail',
emits: ['close'],
props: {
displat: {
type: Boolean,
required: true
},
then in parent component do :
<ModalOrderDetail #close="modal_display=!modal_display" :display="modal_display" :id_order="order_id"/>
But I recommend to use v-model instead of using emitted event and a prop :
<ModalOrderDetail v-model="modal_display" :id_order="order_id"/>
change the display prop to modelValue :
<button type="button" class="btn btn-secondary" #click="$emit('update:modelValue', !modelValue)" >
...
export default {
name: 'ModalOrderDetail',
emits: ['update:modelValue'],
props: {
modelValue: {
type: Boolean,
required: true
},

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

How do you isolate changes in React Props/State

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

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

MVC binding list of object issue

Following my last post MVC model property null on posting form
and by looking in examples, I understand that when I need to post a
list from a view/partialView to the controller I should loop over the list and use
#HiddenFor property and on post, MVC can parse these fields into list.
Somehow the controller is not even been called, only when I remove these lines
#for (int i = 0; i < Model.To.Count; i++)
{
#Html.HiddenFor(m => m.To[i].UserName)
#Html.HiddenFor(m => m.To[i].FirstName)
#Html.HiddenFor(m => m.To[i].LastName)
}
the controller is being called but the sames problem occurs, my list is null.
My view:
#model Mobile.Models.MessageModel
<script type="text/javascript">
$(function () {
$('form').submit(function () {
$.validator.unobtrusive.parse($('form')); //added
if ($(this).valid()) {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
alert("message sent");
$('#messagedetails_panel').toggle();
$("#messages_panel").show();
$("#BtnSuccessMsg").click();
},
error: function (xhr, textStatus, errorThrown) {
alert("message failed");
}
});
}
return false;
});
});
</script>
<table id="messages_panel_mbar" cellpadding="0" cellspacing="0">
<tr>
<td class="left_mbar">
</td>
<td class="main_mbar">
</td>
<td id="back_msg_details" class="right_mbar"></td>
</tr>
</table>
<div style="height:10%; width:100%; font: bold; font-size: 20px; text-align:right;"> #Html.Raw(Model.Subject)</div>
<div id="msg_chat" style="text-align:right; width:100%; height:auto; max-height:80%; overflow-y:scroll;">
#Html.Raw(Model.MsgHistory)
</div>
<div id="reply_msg" style="height: 5%">reply</div>
<div id="reply_msg_block" class="visible" style="width:100%; height:45%;">
#using (Ajax.BeginForm("ReplyMessage", "SettingsMenu", null, new AjaxOptions { }, new { #class = "center_form" }))
{
#Html.ValidationSummary(true, "");
<br />
<fieldset style="height:75%">
#Html.HiddenFor(m => m.Subject)
#Html.HiddenFor(m => m.ParentId)
#Html.HiddenFor(m => m.From)
#Html.HiddenFor(m => m.fullnamesender)
#for (int i = 0; i < Model.To.Count; i++)
{
#Html.HiddenFor(m => m.To[i].UserName)
#Html.HiddenFor(m => m.To[i].FirstName)
#Html.HiddenFor(m => m.To[i].LastName)
}
<div id="textarea_msg_reply">
#Html.TextAreaFor(m => m.Content, new { #class = "" })
#Html.ValidationMessageFor(m => m.Content)
</div>
</fieldset>
<input type="submit" value="send" />
}
</div>
My Controller :
[HttpPost]
public ActionResult ReplyMessage(MessageModel model)// List<Contacts> is empty
{
var errors = ModelState.Values.SelectMany(v => v.Errors);
if (ModelState.IsValid)
{
try
{
model.Send();
}
catch
{
throw new HttpException(404, "Error");
}
}
throw new HttpException(404, "Error");
}
Please advice! Thanks!
Ok, so I figured it out.
I was doing every fine except that the Contact class didn't have a parameterless constructor.
my view:
#model Mobile.Models.MessageModel
<script type="text/javascript">
function showMessagesPanel1() {
$('#messagedetails_panel').toggle();
$("#messages_panel").show();
}
$('#back_msg_details').click(function () {
$.ajax({
url: '#Url.Action("Messages", "SettingsMenu")',
method: 'GET',
success: function (data) {
$("#messages_list").empty();
$("#messages_list").html(data);
$('#messagedetails_panel').toggle();
$("#messages_panel").show();
}
});
})
$('#reply_msg').click(function () {
if ($("#reply_msg_block").is(":visible")) {
$('#msg_chat').animate({ height: '80%' });
// $("#reply_msg_block").slideUp().removeClass('visible');
}
else {
$('#msg_chat').animate({ height: '35%' });
}
$("#reply_msg_block").animate({ heigh: 'toggle' }, 350);
})
$(function () {
$('form').submit(function () {
$.validator.unobtrusive.parse($('form')); //added
if ($(this).valid()) {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
alert("message sent");
$('#messagedetails_panel').toggle();
$("#messages_panel").show();
$("#BtnSuccessMsg").click();
},
error: function (xhr, textStatus, errorThrown) {
$('#reply_msg_block').html(xhr.responseText);
}
});
}
return false;
});
});
</script>
<table id="messages_panel_mbar" cellpadding="0" cellspacing="0">
<tr>
<td class="left_mbar">
</td>
<td class="main_mbar">
</td>
<td id="back_msg_details" class="right_mbar"></td>
</tr>
</table>
<div style="height:10%; width:100%; font: bold; font-size: 20px; text-align:right;"> #Html.Raw(Model.Subject)</div>
<div id="msg_chat" style="text-align:right; width:100%; height:auto; max-height:80%; overflow-y:scroll;">
#Html.Raw(Model.MsgHistory)
</div>
<div id="reply_msg" style="height: 5%">reply</div>
<div id="reply_msg_block" class="visible" style="width:100%; height:45%;">
#using (Ajax.BeginForm("ReplyMessage", "SettingsMenu", null, new AjaxOptions { }, new { #class = "center_form" }))
{
#Html.ValidationSummary(true, "");
<br />
<fieldset style="height:75%">
#Html.HiddenFor(m => m.Subject)
#Html.HiddenFor(m => m.ParentId)
#Html.HiddenFor(m => m.From)
#Html.HiddenFor(m => m.fullnamesender)
#for (int i=0; i<Model.To.Count; i++ )
{
#Html.HiddenFor(m => m.To[i].UserName)
#Html.HiddenFor(m => m.To[i].FirstName)
#Html.HiddenFor(m => m.To[i].LastName)
}
<div id="textarea_msg_reply">
#Html.TextAreaFor(m => m.Content, new { #class = "" })
#Html.ValidationMessageFor(m => m.Content)
</div>
</fieldset>
<input type="submit" value="send" />
}
</div>