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
},
Related
I'm new to angular and this is what I'm trying to achieve:
I have a component that shows a list of users. When the delete action is clicked, a modal dialog appears to ask for confirmation.
I'm not really sure how to pass the id of the user to delete to the delete method.
users.component.html:
<div class="container">
<div style="margin-top:10px;">
<mat-form-field appearance="standard">
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event)" placeholder="Ex: mia" #input>
</mat-form-field>
<div class="mat-elevation-z8">
<table mat-table [dataSource]="dataSource" matSort>
<!-- ID Column -->
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef mat-sort-header> ID </th>
<td mat-cell *matCellDef="let row" id="userid"> {{row.id}} </td>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="email">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Email </th>
<td mat-cell *matCellDef="let row"> {{row.email}} </td>
</ng-container>
<!-- Fruit Column -->
<ng-container matColumnDef="username">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Username </th>
<td mat-cell *matCellDef="let row"> {{row.username}} </td>
</ng-container>
<!-- Fruit Column -->
<ng-container matColumnDef="action">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Action</th>
<td mat-cell *matCellDef="let row" >
<!--
<button mat-icon-button color="warn" (click)="deleteUser(row.id)"> -->
<!---->
<button mat-icon-button color="warn" class="open-exampleModal" data-bs-toggle="modal" data-bs-target="#exampleModal" >
<!--
<button mat-icon-button color="warn" (click)="opendialog()" > -->
<mat-icon>delete</mat-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
<!-- Row shown when there is no matching data. -->
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell" colspan="4">No data matching the filter "{{input.value}}"</td>
</tr>
</table>
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" aria-label="Select page of users"></mat-paginator>
</div>
</div>
</div>
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true" *ngFor="let user of users" >
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Confirmation de la suppression</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
Êtes-vous sûr de vouloir supprimer l'utilisateur?
</div>
<div class="modal-footer">
<button mat-raised-button color="primary" (click)="deleteUser(user.id)" data-bs-dismiss="modal">Supprimer</button>
<button mat-raised-button color="warn" data-bs-dismiss="modal">Annuler</button>
</div>
</div>
</div>
</div>
users.component.ts:
import { Component, OnInit, ViewChild} from '#angular/core';
import { MatDialog, MatTableDataSource, } from '#angular/material';
import { AddUserComponent } from '../add-user/add-user.component';
import { UserServiceService } from '../services/user-service.service';
import {MatPaginator} from '#angular/material/paginator';
import {MatSort} from '#angular/material/sort';
import { User } from '../models/user';
import { FormGroup, FormBuilder, Validators } from '#angular/forms';
#Component({
selector: 'app-users',
templateUrl: './users.component.html',
styleUrls: ['./users.component.css']
})
export class UsersComponent implements OnInit{
displayedColumns: string[] = ['id', 'email', 'username','action'];
users:User[]=[];
dataSource: MatTableDataSource<User>;
userDetail:FormGroup;
#ViewChild(MatPaginator,{static:true}) paginator: MatPaginator;
#ViewChild(MatSort,{static:true}) sort: MatSort;
constructor(private dialog:MatDialog, private userService: UserServiceService, private formBuilder:FormBuilder, ) {
userService.getAllUsers().subscribe((users) => {
for (const user of users) {
const newUser = new User(user.id, user.email, user.username);
this.users.push(newUser);
}
//console.log(this.users);
this.dataSource = new MatTableDataSource<User>(this.users);
this.dataSource.paginator=this.paginator;
this.dataSource.sort=this.sort;
});
}
ngOnInit() {
this.getAllUsers();
this.userDetail=this.formBuilder.group({
username:['',Validators.required],
email:['',Validators.required],
password:['',Validators.required]
})
}
openDialog(){
this.dialog.open(AddUserComponent,{
width:'30%'
});
}
getAllUsers(){
this.userService.getAllUsers()
.subscribe({
next:(res)=>{
this.users=res;
//console.log(res);
console.log(this.users);
this.dataSource=new MatTableDataSource(res);
// this.dataSource = res;
this.dataSource.paginator = this.paginator;
}, error:(err)=>{
alert("error while fetching records");
}
})
}
refresh() {
this.getAllUsers();
this.dataSource.data = [...this.dataSource.data];
this.dataSource.paginator = this.paginator;
}
deleteUser( id:number){
this.userService.deleteUser(id)
.subscribe({
next:(res)=>{
//alert("utilisateur supprimé avec succée!");
this.refresh();
},
error:()=>{
alert("erreur lors de la suppression");
}
});
}
applyFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
if (this.dataSource.paginator) {
this.dataSource.paginator.firstPage();
}
}
}
This way it is always deleting the first record, I'm not sure how to pass the right user id.
I am trying to add some custom logic to my semantic ui validation but can't figure out what I am doing wrong.
Basically, when the user selects "Yes" from the drop-down, I would like to make the "input_field" mandatory. If the user selects "No", the "input_field" becomes optional and the form can be submitted.
I tried searching for examples and followed some code from the Semantic Ui website but can't figure out what I am missing. Any advice would be appreciated as I am on a deadline for a project I am working on.
Form:
<div class="ui dimmer">
<div class="ui huge text loader">Loading</div>
</div>
<form method="post" action="" class="ui form" autocomplete="on">
<div class="ui segment">
<div class="ui two fields">
<div class='field'>
<div class="ui selection dropdown">
<input type="hidden" class="selectOption" name="select">
<i class="dropdown icon"></i>
<div class="default text">Select an option</div>
<div class="menu">
<div class="item" data-value="Yes">Yes</div>
<div class="item" data-value="No">No</div>
</div>
</div>
</div>
<div class="field">
<input id="input_field" name="input_field" type="text"/>
</div>
</div>
</div>
<button id="submit" class="ui green button" name="submit" type="submit">Submit</button>
</form>
Validation:
<script>
$('.ui.form').form({
keyboardShortcuts: false,
on: 'blur',
inline: 'true',
fields: {
selectOption: {
identifier: 'select',
rules: [
{
type: 'empty',
prompt: 'Please select an option'
}]
},
input_field: {
identifier: 'input_field',
depends: 'select',
rules: [
{
type: 'empty',
prompt: function() {
$('.select').on('change', function() {
if( this.value == 'Yes') {
return "Custom Validation";
}
return false;
}).trigger("change");
}
}]
}
},
onSuccess: function() {
$('.ui.dimmer').dimmer('show');
},
onFailure: function() {
event.preventDefault();
}
}
);
});
</script>
Figured out a solution for this! It might not be the best answer but it works and does what I am looking for.
<div class="ui dimmer">
<div class="ui huge text loader">Loading</div>
</div>
<form method="post" action="" class="ui form" autocomplete="on">
<div class="ui segment">
<div class="ui two fields">
<div class='field'>
<div class="ui selection dropdown">
<input type="hidden" class="selectOption" name="select">
<i class="dropdown icon"></i>
<div class="default text">Select an option</div>
<div class="menu">
<div class="item" data-value="Yes">Yes</div>
<div class="item" data-value="No">No</div>
</div>
</div>
</div>
<div class="field">
<input id="input_field" name="input_field" type="text"/>
</div>
</div>
</div>
<button id="submit" class="ui green button" name="submit" type="submit">Submit</button>
</form>
<script>
$('.ui.form').form({
keyboardShortcuts: false,
on: 'blur',
inline: 'true',
fields: {
selectOption: {
identifier: 'select',
rules: [
{
type: 'empty',
prompt: 'Please select an option'
}]
}
},
onSuccess: function() {
$('.ui.dimmer').dimmer('show');
},
onFailure: function() {
event.preventDefault();
}
}
);
$('.selectOption').on('change', function() {
if ( this.value == 'Yes' ) {
$('.ui.form').form('add rule', 'input_field', ['empty', 'integer']);
$('.ui.form').form('add prompt', 'input_field', 'Enter an integer');
}
if ( this.value == 'No' ) {
$('.ui.form').form('remove prompt', 'input_field');
$('.ui.form').form('remove rule', 'input_field');
}
}).trigger("change");
});
</script>
I was able to implement the validation rule by extending Semantic UI setting rules.
See below example:
$.fn.form.settings.rules.dependsOnFieldValue = function (value, dependFieldValue) {
var identifier = dependFieldValue.split('[')[0];
var dependValue = dependFieldValue.match(/\[(.*)\]/i)[1];
if( $('[data-validate="'+ identifier +'"]').length > 0 ) {
matchingValue = $('[data-validate="'+ identifier +'"]').val();
}
else if($('#' + identifier).length > 0) {
matchingValue = $('#' + identifier).val();
}
else if($('[name="' + identifier +'"]').length > 0) {
matchingValue = $('[name="' + identifier + '"]').val();
}
else if( $('[name="' + identifier +'[]"]').length > 0 ) {
matchingValue = $('[name="' + identifier +'[]"]');
}
return (matchingValue !== undefined)
? !( dependValue.toString() === matchingValue.toString() && value === '')
: false
;
};
Then in the form validation initializer you will pass the desired values as below:
$(".ui.form").form({
fields: {
select: {
identifier: 'select',
rules : [
{
type : 'empty'
}
]
},
input_field: {
identifier : 'input_field',
rules : [
{
type : 'dependsOnFieldValue[select[Yes]]',
}
]
},
...
}
});
Notice that we pass the <select> identifier (in this case also called select) within the first [] and then the value that we want to see to make the input_field mandatory ("Yes" in this case).
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.
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"/>
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