I had a problem about views on the website, the display will be right when i do somenthing to display, for example, when i type something in the textbox, it will be displayed correctly and when i resize my browser, the appearance will be true also.
This is example when the display is wrong :
and then this is example when the display is right and this is happened after i resize my browser :
my checkbox treeview will show after i resize my browser.
this is my code, mybe the problem in here :
export class AdministrationMenuGroupEditor{
rows = [];
menuList = [];
selectedMenu: any = [];
//id
public id:number;
public statusForm:string;
//form start
public form:FormGroup;
public submitButtonText:string;
public inHTML5 = true;
public name:AbstractControl;
public description:AbstractControl;
public submitted:boolean = false;
constructor(protected service:AdministrationMenuGroupEditorService, private route: ActivatedRoute, private fb:FormBuilder, _ref: ChangeDetectorRef){
this.route.params.subscribe(params => {
this.id = +params['id'];
});
}
ngOnInit(){
this.submitButtonText = 'Save';
this.form = this.fb.group({
'id': [],
'name': ['', Validators.compose([Validators.required,Validators.minLength(3)])],
'description': []
});
this.name = this.form.controls['name'];
this.description = this.form.controls['description'];
this.service.getMenuGroup()
.subscribe(
data => this.setMenuGroup(data['menuGroup']),
err => this.logError(err),
() => this.finishedGetIndexList('Save')
);
this.statusForm = 'Add';
if(this.id){
this.fetchData();
}
}
setMenuGroup(value){
if (value.length > 0){
this.menuList = value;
console.log(this.menuList);
}
}
fetchData(){
this.service.getIndex(this.id)
.subscribe(
data => this.setValueToForms(data['menuGroup']),
err => this.logError(err),
() => this.finishedGetIndexList('Fetch')
);
}
toggleFormControl(formName:string,value:boolean) : void {
let ctrl = this.form.get(formName);
value==false ? ctrl.disable() : ctrl.enable();
ctrl.markAsUntouched();
}
validationDataInput(value){
if(value == 'name invalid'){
console.log('This name was used, please input different name');
return false;
}
return true;
}
setValueToForms(value) : void {
console.log(value);
if(value.length > 0){
if(this.validationDataInput(value)== true){
this.rows = value[0];
if(this.rows['id']){
this.id = this.rows['id'];
}
this.form.setValue({
'id': this.id,
'name': this.rows['name'],
'description': this.rows['description']
});
this.menuList = value[0]['menuList'];
this.selectedMenu = [];
this.statusForm = 'Edit';
}
}
else{
this.statusForm = 'Add';
}
}
onSubmit(values:Object):void{
values['selectedMenu'] = this.selectedMenu;
this.submitted = true;
this.submitButtonText = 'Saving...';
if (this.form.valid) {
this.service.getSave(values,(this.id)?'edit':'new')
.subscribe(
data => this.succeededSave(data['menuGroup']),
err => this.logError(err),
() => this.finishedGetIndexList(' Save'),
);
}
}
finishedGetIndexList(msg){
console.log('Finish '+msg);
this.submitButtonText = 'Save';
this.submitted = false;
}
logError(errMsg){
let errStatus = errMsg['status'];
window.alert('An error has been detected, please reload this page..');
this.submitButtonText = 'Save';
this.submitted = false;
}
succeededSave(result){
this.setValueToForms(result);
}
}
Is there anyone who can help my problem ?
Related
I develop a project in Angular 9 which reads a csv file and send its content to the server.
I have a model for the file's records.
The request shows the object in "Request payload" but when it get to the API conntroller the data doesn't recognized as [FromBody] parameter.
Do you have any solution for me?
This is my code:
Model:
export class CSVRecord {
public code: string;
public date: Date;
public value: number;
public period: string;
}
Type script:
export class AppComponent {
title = 'FastWayToSerieses-Client';
constructor(public apiService: ApiService, private http: HttpClient ) {
}
public records: any[] = [];
#ViewChild('csvReader') csvReader: any;
uploadListener($event: any): void {
const text = [];
const files = $event.srcElement.files;
if (this.isValidCSVFile(files[0])) {
const input = $event.target;
const reader = new FileReader();
reader.readAsText(input.files[0]);
console.log('after read as text');
reader.onload = (e) => {
console.log('onload');
const csvData = reader.result;
const temp = ( csvData as string).replace(/\r/g, '\n');
const csvRecordsArray = ( temp as string).split(/\r\n|\n/);
const headersRow = this.getHeaderArray(csvRecordsArray);
this.records = this.getDataRecordsArrayFromCSVFile(csvRecordsArray, headersRow.length);
(document.getElementById('sendButton') as HTMLInputElement).disabled = false;
};
} else {
alert('Please import valid .csv file.');
this.fileReset();
}
}
getDataRecordsArrayFromCSVFile(csvRecordsArray: any, headerLength: any) {
console.log('getDataRecordsArrayFromCSVFile');
const csvArr = [];
for (let i = 1; i < csvRecordsArray.length; i++) {
const curruntRecord = (csvRecordsArray[i] as string).split(',');
if (curruntRecord.length === headerLength) {
const csvRecord: CSVRecord = new CSVRecord();
csvRecord.code = curruntRecord[0].trim();
csvRecord.date = new Date(curruntRecord[1].trim());
csvRecord.value = Number(curruntRecord[2].trim());
csvRecord.period = curruntRecord[3].trim();
csvArr.push(csvRecord);
}
}
return csvArr;
}
isValidCSVFile(file: any) {
return file.name.endsWith('.csv');
}
getHeaderArray(csvRecordsArr: any) {
console.log('getHeaderArray');
const headers = (csvRecordsArr[0] as string).split(',');
const headerArray = [];
for (const header of headers){
headerArray.push(header);
}
return headerArray;
}
fileReset() {
this.csvReader.nativeElement.value = '';
this.records = [];
}
This is the function ehich dend the data to the server:
sendCSV(){
console.log('click');
const url = this.apiService.baseUrl + 'API/SeriesAPI/UploadSeriesData?option=1';
// const body = JSON.stringify(this.records);
this.http.post(url, this.records ,
{
headers: new HttpHeaders({
'Content-Type': 'application/json;chrset=UTF-8'
})
}
)
.subscribe(x =>
{
console.log(x);
});
}
Debugger chrome
We are using Vue in our frontend application, and for one of our REST service our backend server(using spring and java) expects to have the below data structure:
public class MAProductsUploadRequest
{
public List<MAProductUploadRequest> products;
}
public class MAProductUploadRequest {
public String productName;
public String productDescription;
public double productPrice;
public int productOrder;
public MultipartFile productImage=null;
public double cropX;
public double cropY;
public double cropWidth;
public double cropHeight;
public int categoryId;
}
And in our Vuejs application we tried to post the data as in the below code:
addProducts: function () {
console.log("Add Products Working. Total Product Count:"+this.excelProducts.length);
let header = {
headers: auth.getAuthHeader()
};
let formData = new FormData();
for (let i=0;i<this.excelProducts.length;i++ ) {
console.log("Starting loop:"+i);
var prod = this.excelProducts[i];
console.log("Product Before:"+prod);
if (document.getElementById('photo-image-'+i) !== null) {
if(document.getElementById('photo-image-'+i).files.length !== 0) {
console.log("Getting Image For Prod");
prod.productImage = document.getElementById('photo-image-'+i).files[0] ;
}
}
prod.cropX = this.cropProp.x;
prod.cropY = this.cropProp.y;
prod.cropWidth = this.cropProp.width;
prod.cropHeight = this.cropProp.height;
prod.rotate = this.cropProp.rotate;
console.log("Product After:"+prod);
formData.append("products[]",prod);
}
for (var pair of formData.entries()) {
console.log(pair[0]+ ', ' + pair[1]);
}
//console.log("Form Data:"+formData.products);
if (formData.products !== null) {
axios.post(`${API_URL}/company/uploadProducts`, formData, header).then((response) => {
logForDevelopment(response);
this.getProducts();
this.product = {
id: '',
name: '',
description: '',
price: '',
photo: '',
isEdit: false
};
this.excelProducts = [];
this.isPhotoChosen = false;
this.isPhotosChosen = [];
this.cropImg = '';
document.getElementById('photo-image').value = null;
this.isLoading = false;
}).catch((error) => {
this.isLoading = false;
if(error.response) {
logForDevelopment(error);
document.getElementById('photo-image').value = null;
if(error.response.status === 401 || error.response.status === 403) {
auth.afterInvalidToken('login');
}
}
})
} else {
console.log("Form Data Is Empty");
}
},
But when we use this code (even if the photo-image was null) the backend server returns HTTP 500 error. Because the products array seems null.
I wasn't able to figure it out where the problem may be in the Vuejs code?
EDIT: (I'VE also tried the below code but the still same result)
addProducts: function () {
console.log("Add Products Working. Total Product Count:"+this.excelProducts.length);
let header = {
headers: auth.getAuthHeader()
};
let formData = new FormData();
let prods = [];
for (let i=0;i<this.excelProducts.length;i++ ) {
console.log("Starting loop:"+i);
let prod = this.excelProducts[i];
let subFormData = new FormData();
subFormData.append("productName",prod.productName);
subFormData.append("productDescription",prod.productDescription);
subFormData.append("productPrice",prod.price);
subFormData.append("categoryId",prod.categoryId);
subFormData.append("cropX",this.cropProp.x);
subFormData.append("cropY",this.cropProp.y);
subFormData.append("cropWidth",this.cropProp.width);
subFormData.append("cropHeight",this.cropProp.height);
prods.push(subFormData);
if (document.getElementById('photo-image-'+i) !== null) {
if(document.getElementById('photo-image-'+i).files.length !== 0) {
console.log("Getting Image For Prod");
subFormData.productImage = document.getElementById('photo-image-'+i).files[0] ;
}
}
}
formData.append("products",prods);
console.log("Form Data:"+formData);
if (formData.products !== null) {
axios.post(`${API_URL}/company/uploadProducts`, formData, header).then((response) => {
logForDevelopment(response);
this.getProducts();
this.product = {
id: '',
name: '',
description: '',
price: '',
photo: '',
isEdit: false
};
this.excelProducts = [];
this.isPhotoChosen = false;
this.isPhotosChosen = [];
this.cropImg = '';
document.getElementById('photo-image').value = null;
this.isLoading = false;
}).catch((error) => {
this.isLoading = false;
if(error.response) {
logForDevelopment(error);
//document.getElementById('photo-image').value = null;
if(error.response.status === 401 || error.response.status === 403) {
auth.afterInvalidToken('login');
}
}
})
} else {
console.log("Form Data Is Empty");
}
},
What I'm actually trying to achive is, our below code works fine when sending single product info to our backend service, but I want to make it an array so send multiple products at once:
addProduct: function () {
let header = {
headers: auth.getAuthHeader()
};
let formData = new FormData();
formData.append('productName', this.product.name);
formData.append('productDescription', this.product.description === '' ? "" : this.product.description);
formData.append('productPrice', this.product.price);
formData.append('categoryId', this.product.categoryId);
if(document.getElementById('photo-image').files.length !== 0) {
formData.append('productImage', document.getElementById('photo-image').files[0]);
}
formData.append('cropX', this.cropProp.x);
formData.append('cropY', this.cropProp.y);
formData.append('cropWidth', this.cropProp.width);
formData.append('cropHeight', this.cropProp.height);
formData.append('rotate', this.cropProp.rotate);
console.log(formData);
axios.post(`${API_URL}/company/products`, formData, header).then((response) => {
logForDevelopment(response);
this.getProducts();
this.product = {
id: '',
name: '',
description: '',
price: '',
photo: '',
isEdit: false
};
this.isPhotoChosen = false;
this.cropImg = '';
document.getElementById('photo-image').value = null;
this.isLoading = false;
}).catch((error) => {
this.isLoading = false;
if(error.response) {
logForDevelopment(error);
document.getElementById('photo-image').value = null;
if(error.response.status === 401 || error.response.status === 403) {
auth.afterInvalidToken('login');
}
}
})
},
Does anyone have any idea about that?
You can also look at the screenshot of my application in below(I want to send all the items in screenshot , at once )
Your issue is probably il the formData.append("products[]",prod) method of your FormData class, try changing formData.append("products[]",prod) with formData.products.push(prod).
Furthermore in your axios call the payload should be formData.products if you API endpoint expects the products right?
Try axios.post(${API_URL}/company/uploadProducts, formData.products, header).
I do not see any syntax issue relative to Vue, hope this helps. (And of course check what is sent by XHR in devtools as suggested in the comments)
Hi I am trying to authenticate users and once the server gives user's information, I want to use the information of the user.
But for some reasons, even though I did the log in process without any error and I can see from developer's tool that the POST request has been successful, I can't quite set currentUser in my localStorage (giving me null if I console.log it)
What am I doing wrong?
This is my authentication service.
export class AuthenticationService {
constructor(private http: Http, private router: Router) { }
login(email: string, password: string): Observable<User>{
const headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
headers.append('Access-Control-Allow-Headers', 'Content-Type');
headers.append('Access-Control-Allow-Methods', 'post');
headers.append('Access-Control-Allow-Origin', '*');
headers.append("X-Requested-With", "XMLHttpRequest");
let options = new RequestOptions({ headers: headers });
let body = new URLSearchParams();
body.set('email', email);
body.set('password', password);
return this.http.post(`${environment.baseurl}` + '/api/v2/member/login', body, options)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let user = res.json();
if (user && user.token) {
localStorage.setItem('currentUser', JSON.stringify(user));
}
return user.data || {};
}
logout() {
// remove user from local storage to log user out
localStorage.removeItem('currentUser');
}
private handleError(error: any) {
if (error.status === 401) {
return Observable.throw(error.status);
} else {
return Observable.throw(error.status || 'Server error');
}
}
}
And this is my log-in component
export class LoginPageComponent implements OnInit {
constructor(private location: Location,
private route: ActivatedRoute,
private router: Router,
private authenticationService: AuthenticationService,
private alertService: AlertService) {
}
model: any = {};
loading = false;
returnUrl: string;
error = '';
ngOnInit() {
// get return url from route parameters or default to '/'
this.returnUrl = this.route.snapshot.queryParams['main'] || '/';
}
currentUser: User;
login() {
this.loading = true;
this.authenticationService.login(this.model.email, this.model.password)
.subscribe(
data => {
this.currentUser = data;
this.router.navigate([this.returnUrl]);
},
error => {
this.error = "Wrong ID or PW";
this.loading = false;
});
}
backClicked() {
this.location.back();
}
}
And this is my home component
export class MainComponent {
onClick() {
this.auth.logout() //if user clicks logout button
}
currentUser: User;
users: User[] = [];
items: Object[] = [];
constructor(private authguard: AuthGuard, private auth:AuthenticationService) {
this.currentUser = JSON.parse(localStorage.getItem('currentUser'));
console.log(localStorage.getItem('currentUser')); //Printing null
}
}
And the model for user information is this.
export interface User {
birthday: number;
email:string;
genderType:string;
memberType: string;
name: string;
phone: string;
}
What im receiving
Why is it printing null?
Thank you!
Mistakes you made
passing email and password as URLSearchParams.
You are adding all the headers to your login method which is not necessary
The service should contain method as below
login(body: any, options?: RequestOptionsArgs): Observable<Response> {
return this.http.post('loginUrl', body);
}
Component should contain the below code
login() {
let user ={
email : this.model.email
password : this.model.password)
}
this.loading = true;
this.authenticationService.login(user)
.subscribe(data => {
this.authenticationService.extractData(data);///call to store token in the localstorage
this.router.navigate([this.returnUrl]);
},
error => {
this.error = "Wrong ID or PW";
this.loading = false;
});
}
i have struggles with the local storage parameter i have this //error SyntaxError at JSON.parse ()// i get " undefined" instead of the real values any help please on how to retrieve parameters from LocalStorage that i set after login in both my service auth-service.ts and auth.ts??!!
auth-service.ts
public loginChef(credentials) {
if (credentials.email === null || credentials.password === null) {
return Observable.throw("Please insert credentials");
} else {
return Observable.create(observer => {
var url = 'http://localhost/PFEBACKEND/login-chef.php?
email='+credentials.email+'&passe='+credentials.password ;
this.http.get(url).map(res => res.json()).subscribe(
data=>{
let access = (data.error=== 0 )
localStorage.setItem('nom',data.nom_contact);
localStorage.setItem('nom_societe',data.nom_societe);
localStorage.setItem('email',data.email);
localStorage.setItem('telephone',data.telephone);
localStorage.setItem('matricule_fiscale',data.matricule_fiscale);
localStorage.setItem('role',data.role);
localStorage.setItem('id',data.id_chef);
this.member=data;
this.email=data.email;
this.nom=data.nom;
// this.currentUser = new User( data.nom,data.email);
observer.next(this.email,this.nom);
//observer.next(this.member);
//observer.next(access);
// console.log(this.currentUser);
observer.complete();
},
err => {
console.log(err);
observer.next(err);
},
() => console.log('service observable') );
});
}
}
offre.ts
offres: Array<any>;
loader: any;
id:string='';
constructor(public navCtrl: NavController, public navParams: NavParams,
public data:Datamembers,private auth:AuthService, public
loadingCtrl:LoadingController)
{
if(localStorage.getItem('id')){//after login i store the user data
this.id=localStorage.getItem('id');
}
}
ngOnInit()
{ var id1=parseInt(this.id).valueOf();// i get undefined value
this.presentLoading();
this.data.LoadOffres(id1).subscribe(
//function LoadOffres accept int type parameter
data => {
this.offres = data;
console.log(data);
this.loader.dismiss();
},
err => {
console.log(err);
console.log(id1);
this.loader.dismiss();
},
() => console.log('chargement terminé')
);
}
auth.ts
public loginChef() {
this.showLoading();
this.auth.loginChef(this.registerCredentials).subscribe(allowed => {
if (allowed) {
setTimeout(() => {
this.email=this.auth.email;
this.nom=this.auth.nom;
this.currentUSer = this.auth.currentUser;
this.member=this.auth.member;//array
localStorage.setItem('email',this.email);
localStorage.setItem('nom',this.nom);
(....)
everything is right the problem was in my server side code
I have a mvc application with a kendo Grid
Here's the view code
#using Domain.Agromilieu2.Wui.Resources.Bedrijfsgegevens.Views
#using Domain.Agromilieu2.Wui.Models.BeheerTeksten
#model TekstenViewModel.Main
#{
Layout = WebCore.Views.Layouts.Extended;
}
<h2>Teksten</h2>
#(Html.Kendo().Window()
.Name("alertWindow")
.Title("Status Message from Server")
.Draggable()
.Resizable()
.Width(400)
.Height(200)
.Modal(true)
.Visible(false)
.Actions(actions => actions.Close())
)
#Html.WebCore().Popup.CustomButtons("popupDemo", "Waarde", Html.Kendo().Editor().Name("waardeEditor").HtmlAttributes(new { #class = "editorStyle" }).Tools(tools => tools
.Clear()
.Bold().Italic().Underline().Strikethrough()
.JustifyLeft().JustifyCenter().JustifyRight().JustifyFull()
.InsertUnorderedList().InsertOrderedList()
.Outdent().Indent()
.CreateLink().Unlink()
.InsertImage()
.SubScript()
.SuperScript()
.TableEditing()
.ViewHtml()
.Formatting()
.FontName()
.FontSize()
.FontColor().BackColor()
).ToHtmlString(), new[]{new PopupButton("popupDemoAnnuleren", "Cancel", false),new PopupButton("popupDemoOk", "OK")})
<div class="infoPanel">
<div id='divSousMenu'>
<div>
<h2 class="zoekCriteria">ZOEKCRITERIA</h2>
<h4 class="resourceSet">Resource Set:</h4>
#(Html.Kendo().ComboBoxFor(model => model.Filter.userName)
.Name("resourcesSetComboBox")
.DataTextField("Naam")
.DataValueField("ID")
.Filter(FilterType.Contains)
.HtmlAttributes(new { #class = "comboStyle" })
.DataSource(source =>
{
source.Read(read =>
{
read.Action(MVC.BeheerTeksten.ActionNames.ResourceSetsIntoCombo_Read, MVC.BeheerTeksten.Name)
.Data("onAdditionalData");
})
.ServerFiltering(true);
})
.AutoBind(false)
)
</div>
<div class='gewijzigdItem'>
<h4 class="gewijzigdDoor">Gewijzigd door:</h4>
#(Html.Kendo().ComboBox()
.Name("usersSetComboBox")
.DataTextField("DisplayName")
.DataValueField("UserName")
.Filter(FilterType.Contains)
.HtmlAttributes(new { #class = "comboStyle" })
.DataSource(source =>
{
source.Read(read =>
{
read.Action(MVC.BeheerTeksten.ActionNames.GebruikersIntoCombo_Read, MVC.BeheerTeksten.Name)
.Data("onAdditionalData");
})
.ServerFiltering(true);
})
.AutoBind(false)
)
</div>
<div class='vanItem'>
<h4 class="van">Van:</h4>
#(Html.Kendo().DateTimePicker()
.Name("vanTimepicker")
.Max(DateTime.Today)
.Events(events => events.Change("onVanTimeChange"))
.HtmlAttributes(new { #class = "dateTimePickerStyle;" })
)
</div>
<div class='totItem'>
<h4 class="tot">Tot:</h4>
#(Html.Kendo().DateTimePicker()
.Name("totTimepicker")
.Max(DateTime.Today)
.Events(events => events.Change("onTotTimeChange"))
.HtmlAttributes(new { #class = "dateTimePickerStyle;" })
)
</div>
</div>
</div>
<div class="separator"></div>
#*<hr />*#
<div class="zoekResultatLine">
<h2 class="zoekResultat">ZOEKRESULTAAT</h2>
</div>
#(Html.Kendo().Grid<TekstenViewModel.Tekst>()
.Name("Grid")
.Columns(columns =>
{
columns.Template(#<text></text>).ClientTemplate("<input type='checkbox'/>").Width(10).Hidden(!Model.Administrator);
columns.Bound(product => product.RESOURCE_SET_NAAM).Width(125).ClientTemplate("#= RESOURCE_SET_NAAM#");
columns.Bound(product => product.Naam).Width(125).ClientTemplate("#= Naam#");
columns.Bound(product => product.Waarde).Width(125).ClientTemplate("<div id='editorDiv'><div class='input'>#=Waarde#</div><div class='editor'>" +
Html.WebCore().LinkButton(type: ButtonType.MeerActies, htmlAttributes: new { onclick = "openPopupDemo('#: Waarde #', '#: ID #', 'Waarde')" }));
columns.Bound(product => product.Opmerking).Width(250).ClientTemplate("<div id='editorDiv'><div class='input'>#=Opmerking#</div><div class='editor'>" +
Html.WebCore().LinkButton(type: ButtonType.MeerActies, htmlAttributes: new { onclick = "openPopupDemo('#: Opmerking #', '#: ID #', 'Opmerking')" }));
columns.Template(#<text></text>).ClientTemplate("<div id='deleteDiv'><div class='delete'><a class=\"delete iconBtn\" onclick=\"deleteResourceItem(#: ID #, '#: Naam #')\"></a></div></div>").Width(10).Hidden(!Model.Administrator);
})
.Pageable()
.Sortable()
.Filterable()
.Events(events => events.Edit("onCellEdit").DataBinding("onDataBinding"))
.Groupable()
.Navigatable()
.Editable(editable => editable.Mode(GridEditMode.InCell).DisplayDeleteConfirmation(false))
.DataSource(dataSource => dataSource
.Ajax()
.Batch(true)
.Events(e => e.Error("error_handler"))
.Model(model =>
{
model.Id(product => product.ID);
model.Field(product => product.Naam).Editable(Model.Administrator);
model.Field(product => product.Opmerking).Editable(Model.Administrator);
model.Field(product => product.Waarde).Editable(!Model.ReadOnly);
model.Field(product => product.RESOURCE_SET_ID).DefaultValue(Model.SetID);
model.Field(product => product.Type).DefaultValue(Domain.Agromilieu2.Common.Objects.Entities.Resources.ResourceType.GLOBAL_RESOURCES);
model.Field(product => product.Taal).DefaultValue(Domain.Agromilieu2.Common.Agromilieu2Constants.Resources.DEFAULT_TAAL_CODE);
})
.Create(create => create.Action(MVC.BeheerTeksten.ActionNames.ResourceItems_Create, MVC.BeheerTeksten.Name))
.Read(read => read.Action(MVC.BeheerTeksten.ActionNames.ResourceItems_Read, MVC.BeheerTeksten.Name, new { setID = Model.SetID }).Data("onReadAdditionalData"))
.Update(update => update.Action(MVC.BeheerTeksten.ActionNames.ResourceItems_Update, MVC.BeheerTeksten.Name))
.Destroy(destroy => destroy.Action(MVC.BeheerTeksten.ActionNames.ResourceItems_Delete, MVC.BeheerTeksten.Name))
)
)
#Html.WebCore().Popup.Remove("confirmResourceItemPopup", "Verwijderen resource item", "")
#section Scripts
{
#Scripts.Render(Links.Bundles.Scripts.BeheerTeksten.Teksten)
<script type="text/javascript">
function onCellEdit(e) {
var grid = $("#Grid").data("kendoGrid");
var row = $(e.container).closest("tr");
var colIdx = $("td", row).index($(e.container));
var columname = e.sender.columns[colIdx].field;
e.container.find("[name='" + columname + "']").toggleClass('editInput');
}
function onDataBinding(e) {
var grid = $("#Grid").data("kendoGrid");
if ($("#resourcesSetComboBox").data("kendoComboBox").value() == "")
grid.showColumn(1);
else
grid.hideColumn(1);
}
function onVanTimeChange() {
var vanTimeValue = kendo.toString($("#vanTimepicker").data("kendoDateTimePicker").value(), "dd/MM/yyyy HH:mm:ss.ffff")
$("#totTimepicker").data("kendoDateTimePicker").min(vanTimeValue);
}
function onTotTimeChange() {
var totTimeValue = kendo.toString($("#totTimepicker").data("kendoDateTimePicker").value(), "dd/MM/yyyy HH:mm:ss.ffff")
$("#vanTimepicker").data("kendoDateTimePicker").max(totTimeValue);
}
function onAdditionalData() {
var code = window.location.pathname.split('/');
return {
toepassingsCode: code[5]
};
}
function onReadAdditionalData() {
var resourceID = $.urlParam('setID');
if (resourceID) {
$("#resourcesSetComboBox").data("kendoComboBox").value(resourceID);
$("#resourcesSetComboBox").data("kendoComboBox").enable(false);
}
else
resourceID = $("#resourcesSetComboBox").data("kendoComboBox").value();
var user = $.urlParam('userName');
if (user) {
$("#usersSetComboBox").data("kendoComboBox").value(user);
$("#usersSetComboBox").data("kendoComboBox").enable(false);
}
else
user = $("#usersSetComboBox").data("kendoComboBox").value();
var vanTimeValue = $.urlParam('vanTime');
if (vanTimeValue) {
$("#vanTimepicker").data("kendoDateTimePicker").value(new Date(Date.parse(vanTimeValue, "dd/MM/yyyy HH:mm:ss")));
$("#vanTimepicker").data("kendoDateTimePicker").enable(false);
}
else
var vanTimeValue = kendo.toString($("#vanTimepicker").data("kendoDateTimePicker").value(), "dd/MM/yyyy HH:mm:ss.ffff")
var totTimeValue = $.urlParam('totTime');
if (totTimeValue) {
$("#totTimepicker").data("kendoDateTimePicker").value(totTimeValue);
$("#totTimepicker").data("kendoDateTimePicker").enable(false);
}
else
var totTimeValue = kendo.toString($("#totTimepicker").data("kendoDateTimePicker").value(), "dd/MM/yyyy HH:mm:ss.ffff")
return {
setID: resourceID,
userName: user,
vanTime: vanTimeValue,
totTime: totTimeValue
};
}
$.urlParam = function (name) {
var enc = decodeURI(window.location.href);
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(enc);
if (results != null)
return results[1];
}
function deleteResourceItem(resourceItemID, resourceItemName) {
domain.Agromilieu2.Wui.BeheerTeksten.Teksten.deleteResourceItem(resourceItemID, resourceItemName);
}
var selectedGridRowID = 0;
var selectedGridColumnName;
function openPopupDemo(gridCellContent, gridIdentifier, columnIdentifier) {
var editor = $("#waardeEditor").data("kendoEditor")
if (('#Html.Raw(Json.Encode(Model.ReadOnly))' == "false" && '#Html.Raw(Json.Encode(Model.Administrator))' == "false" && columnIdentifier != "Waarde") || '#Html.Raw(Json.Encode(Model.ReadOnly))' == "true")
editor.body.contentEditable = false;
else
editor.body.contentEditable = true;
editor.value(htmlDecode(gridCellContent));
domain.WebCore.popup.show("popupDemo");
selectedGridRowID = gridIdentifier;
selectedGridColumnName = columnIdentifier;
};
function htmlDecode(value) {
return $('<div/>').html(value).text();
}
function htmlEncode(value) {
return $('<div/>').text(value).html();
}
function htmlEscape(str) {
return String(str)
.replace(/"/g, '"')
.replace(/'/g, ''')
}
domain.WebCore.popup.configure("popupDemo")
.click(function (b) {
var grid = $("#Grid").data("kendoGrid");
var editor = $("#waardeEditor").data("kendoEditor")
var parentItem = grid.dataSource.get(selectedGridRowID);
parentItem.set(selectedGridColumnName, htmlEscape(htmlEncode(editor.value())));
});
function showAlertWindow(message) {
var alertWindow = $('#alertWindow').data('kendoWindow');
alertWindow.content(message);
alertWindow.refresh();
alertWindow.center();
alertWindow.open();
}
function error_handler(e) {
if (e.errors) {
var message = "";
$.each(e.errors, function (key, value) {
if ('errors' in value) {
$.each(value.errors, function () {
message += this + "\n";
});
}
});
showAlertWindow(message);
}
}
$(function () {
domain.Agromilieu2.Wui.BeheerTeksten.Teksten.init(
{
deleteResourceItemUrl: "#Url.Action(MVC.BeheerTeksten.ResourceItems_Delete())",
deleteResourceItemMessage: "<p>Bent u zeker dat u '{0}' wil verwijderen?</p><p><strong>Opgelet!</strong><br>Hierbij worden ook alle teksten verbonden aan deze resource set verwijderd.</p>",
ResourceItems_ReadUrl: "#Url.Action(MVC.BeheerTeksten.ResourceItems_Read())"
});
});
</script>
}
And here's my controller's code.
// GET /Agromilieu2/Beheer/Teksten/Teksten
[HttpGet]
[Domain.BasisArchitectuur.Framework.MVC.ActionFilters.MenuItem("Teksten")]
[IsAgromilieuActieAllowed(ActieClaims.TekstenRaadpleger)]
public virtual ActionResult Teksten(string toepassingsCode = null, long? setID = null, string taalCode = null, string resourceType = null, string user = null)
{
bool admin = SecurityHelper.IsActieAllowed(ActieClaims.TekstenAdmin);
LayoutService.SubTitle = DetailResources.TITEL_Header;
if (admin)
{
LayoutService.SubmitActions = new List<LinkButton>
{
new LinkButton { ButtonType = ButtonType.Toevoegen, CssClass = "myToevoegenButton", IsDisabled = setID == null, ClientId = "teste" },
new LinkButton { ButtonType = ButtonType.Delete, CssClass = "myVerwijderenButton" },
new LinkButton { ButtonType = ButtonType.Zoeken, CssClass = "primair myZoekenButton" }
};
}
else
{
LayoutService.SubmitActions = new List<LinkButton>
{
new LinkButton { ButtonType = ButtonType.Zoeken, CssClass = "primair myZoekenButton" }
};
}
if (string.IsNullOrEmpty(toepassingsCode))
{
return RedirectToAction(MVC.BeheerTeksten.Toepassingen());
}
else
{
if (!string.IsNullOrEmpty(resourceType) && resourceType == ResourceType.REFE_RESOURCES)
{
return RedirectToAction(MVC.BeheerTeksten.RefeTeksten(toepassingsCode, setID, taalCode));
}
else
{
if (string.IsNullOrEmpty(taalCode))
{
taalCode = Agromilieu2Constants.Resources.DEFAULT_TAAL_CODE;
}
LayoutService.SubTitle = string.Format("Beheer Teksten - {0}",
BL.Resources.Resources.GetToepassingen().First(x => x.Code == toepassingsCode).Omschrijving);
TekstenViewModel.Main model = new TekstenViewModel.Main
{
DefaultTaal = Agromilieu2Constants.Resources.DEFAULT_TAAL_CODE,
Filter = new TekstenViewModel.ZoekCriteria
{
ResourceSet_ID = setID,
Taal = taalCode,
userName = user
},
ToepassingsCode = toepassingsCode,
SetID = setID,
ReadOnly = !(SecurityHelper.IsActieAllowed(ActieClaims.TekstenAdmin) || SecurityHelper.IsActieAllowed(ActieClaims.TekstenBeheer)),
Administrator = SecurityHelper.IsActieAllowed(ActieClaims.TekstenAdmin)
};
return View(model);
}
}
}
[HttpPost]
[Domain.BasisArchitectuur.Framework.MVC.ActionFilters.MenuItem("Teksten")]
[IsAgromilieuActieAllowed(ActieClaims.TekstenRaadpleger)]
public virtual ActionResult ResourceItems_Read([DataSourceRequest]DataSourceRequest request, long? setID, string userName, string vanTime, string totTime, string taalCode = Agromilieu2Constants.Resources.DEFAULT_TAAL_CODE)
{
DateTime? newVanTime = null;
DateTime? newTotTime = null;
if(!String.IsNullOrEmpty(vanTime))
newVanTime = DateTime.Parse(vanTime);
if (!String.IsNullOrEmpty(totTime))
newTotTime = DateTime.Parse(totTime);
TekstenViewModel.ZoekCriteria searchCriteria = new TekstenViewModel.ZoekCriteria
{
ResourceSet_ID = setID,
type_Code = ResourceType.GLOBAL_RESOURCES,
Taal = taalCode,
userName = userName,
vanTime = newVanTime,
totTime = newTotTime
};
List<TekstenViewModel.Tekst> resourceItemsList = new List<Models.BeheerTeksten.TekstenViewModel.Tekst>();
resourceItemsList = GetResourceItemsList(searchCriteria);
return Json(resourceItemsList.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
[AcceptVerbs(HttpVerbs.Post)]
[Domain.BasisArchitectuur.Framework.MVC.ActionFilters.MenuItem("Teksten")]
[IsAgromilieuActieAllowed(ActieClaims.TekstenBeheren)]
public virtual ActionResult ResourceItems_Create([DataSourceRequest]DataSourceRequest request, [Bind(Prefix = "models")]IEnumerable<TekstenViewModel.Tekst> resourceItems)
{
List<ResourceItemDto> entities = new List<ResourceItemDto>();
if (ModelState.IsValid)
{
try
{
using (IProxy<IResourceService> proxy = _proxyFactory.Create<IResourceService>())
{
foreach (TekstenViewModel.Tekst tekstenViewModel in resourceItems)
{
ResourceItemDto resourceItem = new ResourceItemDto
{
ResourceItem_ID = tekstenViewModel.ID,
ResourceSet_ID = tekstenViewModel.RESOURCE_SET_ID,
Naam = HttpUtility.HtmlDecode(tekstenViewModel.Naam),
Opmerking = HttpUtility.HtmlDecode(tekstenViewModel.Opmerking),
Waarde = HttpUtility.HtmlDecode(tekstenViewModel.Waarde),
Type_Code = tekstenViewModel.Type,
Taal_Code = tekstenViewModel.Taal,
ResourceWaarde_ID = tekstenViewModel.WAARDE_ID
};
entities.Add(resourceItem);
}
proxy.Client.CheckIfNameExists(entities);
proxy.Client.AddOrUpdateResourceItem(entities.AsEnumerable());
}
}
catch (Exception ex)
{
ModelState.AddModelError(string.Empty, ex.Message);
}
}
else
{
var errMsg = ModelState.Values
.Where(x => x.Errors.Count >= 1)
.Aggregate("Model State Errors: ", (current, err) => current + err.Errors.Select(x => x.ErrorMessage));
ModelState.AddModelError(string.Empty, errMsg);
}
//ModelState.AddModelError("Naam", );
//resourceItems = GetResourceItemsList(new TekstenViewModel.ZoekCriteria { Taal = resourceItems.FirstOrDefault().Taal, ResourceSet_ID = resourceItems.FirstOrDefault().RESOURCE_SET_ID });
return Json(entities.ToDataSourceResult(request, ModelState));
}
[AcceptVerbs(HttpVerbs.Post)]
[Domain.BasisArchitectuur.Framework.MVC.ActionFilters.MenuItem("Teksten")]
[IsAgromilieuActieAllowed(ActieClaims.TekstenBeheren)]
public virtual ActionResult ResourceItems_Update([DataSourceRequest]DataSourceRequest request, [Bind(Prefix = "models")]IEnumerable<TekstenViewModel.Tekst> resourceItems)
{
List<ResourceItemDto> entities = new List<ResourceItemDto>();
if (ModelState.IsValid)
{
try
{
using (IProxy<IResourceService> proxy = _proxyFactory.Create<IResourceService>())
{
foreach (TekstenViewModel.Tekst tekstenViewModel in resourceItems)
{
ResourceItemDto resourceItem = new ResourceItemDto
{
ResourceItem_ID = tekstenViewModel.ID,
ResourceSet_ID = tekstenViewModel.RESOURCE_SET_ID,
Naam = HttpUtility.HtmlDecode(tekstenViewModel.Naam),
Opmerking = HttpUtility.HtmlDecode(tekstenViewModel.Opmerking),
Waarde = HttpUtility.HtmlDecode(tekstenViewModel.Waarde),
Type_Code = tekstenViewModel.Type,
Taal_Code = tekstenViewModel.Taal,
ResourceWaarde_ID = tekstenViewModel.WAARDE_ID
};
entities.Add(resourceItem);
}
proxy.Client.AddOrUpdateResourceItem(entities.AsEnumerable());
}
}
catch (Exception ex)
{
ModelState.AddModelError(string.Empty, ex.Message);
}
}
else
{
var errMsg = ModelState.Values
.Where(x => x.Errors.Count >= 1)
.Aggregate("Model State Errors: ", (current, err) => current + err.Errors.Select(x => x.ErrorMessage));
ModelState.AddModelError(string.Empty, errMsg);
}
return Json(resourceItems.ToDataSourceResult(request, ModelState));
}
[HttpDelete]
[IsAgromilieuActieAllowed(ActieClaims.TekstenBeheren)]
public virtual ActionResult ResourceItems_Delete(long? id)
{
using (IProxy<IResourceService> proxy = _proxyFactory.Create<IResourceService>())
{
proxy.Client.DeleteResourceItemRecursively(id);
}
return Content(CoreService.LastMainScreenUrl ?? MvcConfig.DefaultStartupUrl);
}
[HttpPost]
[IsAgromilieuActieAllowed(ActieClaims.TekstenBeheren)]
public virtual ActionResult ResourceItems_Delete( [Bind(Prefix="models")] List<TekstenViewModel.Tekst> resourceItems)
{
using (IProxy<IResourceService> proxy = _proxyFactory.Create<IResourceService>())
{
foreach(TekstenViewModel.Tekst resourceItem in resourceItems )
{
proxy.Client.DeleteResourceItemRecursively(resourceItem.ID);
}
}
return Content(CoreService.LastMainScreenUrl ?? MvcConfig.DefaultStartupUrl);
}
[HttpGet]
[IsAgromilieuActieAllowed(ActieClaims.TekstenRaadpleger)]
public virtual JsonResult ResourceSetsIntoCombo_Read(string toepassingsCode)
{
ResourceWcfDataServiceProxy proxy = DependencyResolver.Current.GetService<ResourceWcfDataServiceProxy>();
IEnumerable<ResourceSetsViewModel.ResourceSet> sets =
Enumerable.Repeat(new ResourceSetsViewModel.ResourceSet { Naam = "Maak een selectie" }, 1).Union(proxy.ResourceSetSet
.Where(s => s.ToepassingsCode == toepassingsCode)
.Select(s => new
{
ID = s.ID,
Naam = s.Naam,
Opmerking = s.Opmerking,
Type = s.Type.Code
}).ToList()
.Select(s => new ResourceSetsViewModel.ResourceSet
{
ID = s.ID,
Naam = s.Naam,
Opmerking = s.Opmerking,
Type = s.Type
}));
return Json(sets.ToList(), JsonRequestBehavior.AllowGet);
}
[HttpGet]
[IsAgromilieuActieAllowed(ActieClaims.TekstenRaadpleger)]
public virtual JsonResult GebruikersIntoCombo_Read(string toepassingsCode)
{
IEnumerable<TekstenViewModel.UserInfo> journalingUsers;
using (IProxy<IResourceService> proxy = _proxyFactory.Create<IResourceService>())
{
journalingUsers = Enumerable.Repeat(new TekstenViewModel.UserInfo { UserName = null, DisplayName = "Maak een selectie" }, 1)
.Union(proxy.Client.GetUsers(toepassingsCode).Select(x => new TekstenViewModel.UserInfo { UserName = x, DisplayName = x }));
}
return Json(journalingUsers.ToList(), JsonRequestBehavior.AllowGet);
}
When I update, read or delete, everything works fine. When I create, it's like I'm not getting back the right data in the grid.
I mean, I create a new record and press Save, it calls the savechanges event of the grid. So far so good, but if I press Save again, it calls the savechanges event again and I get this error.
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
Here's a picture of the grid before creating a new record.
Here's a picture of the grid after inserting a new record
The first record should be the last. Have no idea why this is happening.