Dgrid + Selection Issue - dgrid

Still trying to work with Dgrid (0.4) and dojo (1.10), I have now another issue with the selection.
My web page contain a Dialog opened when you click on a button.
Inside this dialog, we have the following code which display a grid with data coming from a database through a Json HTTP page. This is working fine, even sorting and query filtering.
What I want to do know is to allow the user to double click on a row, get the selected row Id contains in the first column to update the form in the main page. I use the dgrid/selection for this. However, it always return the last row of the grid instead of the one the user selected.
The selection code is based on this :
http://dgrid.io/tutorials/0.4/hello_dgrid/
Any idea?
Thanks
<script language="javascript">
require
(
[
"dojo/_base/declare",
"dojo/_base/array",
"dgrid/OnDemandList",
"dgrid/OnDemandGrid",
"dgrid/Keyboard",
"dgrid/Selection",
"dgrid/Editor",
"dgrid/extensions/ColumnHider",
"dstore/Memory",
"dstore/RequestMemory",
"dojo/_base/lang",
"dojo/dom-construct",
"dojo/dom",
"dojo/on",
"dojo/when",
"dojo/query",
"dojo/store/Observable",
"dstore/Rest",
"dojo/_base/Deferred",
"dojo/store/Cache",
"dojo/domReady!",
],
function(
declare, arrayUtil, OnDemandList, OnDemandGrid, Keyboard, Selection, Editor, ColumnHider, Memory, RequestMemory, lang, ObjectStore, dom, on, when, query, Observable, Rest, Deferred
){
var fform = dom.byId("filterForm");
var ContactColumns = [
{ label: "", field: "contact_id", hidden: true, unhidable: true},
{ label: "Company Name", field: "company_name", unhidable: true },
{ label: "Contact Name", field: "contact_name", unhidable: true },
{ label: "Email", field: "contact_email", unhidable: true }
];
var ContactGrid=declare([OnDemandGrid, Keyboard, Selection,ColumnHider]);
var contactlist = new Observable(new Rest({ target: './ajax.contactsLoader.php' }));
var selection = [];
window.contactgrid = new ContactGrid(
{
className: "dgrid-selectors",
collection: contactlist,
maxRowsPerPage:10,
selectionMode: 'single',
cellNavigation: false,
columns: ContactColumns
}, "contacttable"
);
on(fform, "submit", function (event) {
var cpy_filter = fform.elements.fcompany_name.value;
var ct_filter = fform.elements.fcontact_name.value;
var email_filter = fform.elements.fcontact_email.value;
contactgrid.set('collection',contactlist.filter({contact_name: ct_filter, company_name: cpy_filter, contact_email: email_filter }));
contactgrid.refresh();
event.preventDefault();
});
contactgrid.on('dgrid-select', function (event) {
// Report the item from the selected row to the console.
console.log('Row selected: ', event.rows[0].data);
});
contactgrid.on('dgrid-deselect', function (event) {
console.log('Row de-selected: ', event.rows[0].data);
});
contactgrid.on('.dgrid-row:click', function (event) {
var row = contactgrid.row(event);
console.log('Row clicked:', row.data);
});
}
);
</script>
<div class="dijitDialogPaneContentArea" style="width:96%;margin-left:5px">
<form id="filterForm">
<div class="dijitDialogPaneActionBar" >
<button data-dojo-type="dijit.form.Button" type="submit">Filter</button>
<button
data-dojo-type="dijit.form.Button"
data-dojo-attach-point="submitButton"
type="submit"
>
Select
</button>
<button
data-dojo-type="dijit.form.Button"
data-dojo-attach-point="cancelButton"
>
Close
</button>
</div>
<div data-dojo-attach-point="contentNode" >
<input type="text" data-dojo-type="dijit.form.TextBox" name="fcompany_name" id="fcompany_name" style="width:33%">
<input type="text" data-dojo-type="dijit.form.TextBox" name="fcontact_name" id="fcontact_name" style="width:32%">
<input type="text" data-dojo-type="dijit.form.TextBox" name="fcontact_email" id="fcontact_email" style="width:33%">
<div id="contacttable">
</div>
</div>
</form>
</div>

Just found the reason.
the columns need to have a 'id' column called ID. I just change the 'contact_id' column to 'id' and it works fine.
thanks

Related

Button press triggers the last button's press

I'm new to react an am trying to create an app to use in my portfolio. Essentially the program is a menu that has access to different menus(json files: texas_pick.js, breakfast.js...), the program is meant to display the menu options in form of buttons, the buttons' details are retrieved from their respective json file. The problem that I am facing is that when making a click on a menu option the data of the last menu item is retrieved. I programmed the backend to only push the item's name and price to the database, and the frontend, to retrieve this data and display it on a table. The data retrieved is only the last button's and not any others. I believe the problem to possibly be within my button code. Any help/tips/recommendations you could give are greatly appreciated.
I clicked every menu item and only the data from the last one was retrieved
import React from 'react'
import {useEffect,useState} from 'react'
import axios from 'axios'
import Texas_Pick from '../../json_files/texas_pick.json'
import './Mid_Container.css'
function Mid_Container() {
const [items, setItems] = useState(Texas_Pick);
const [order, setOrder] = useState({
item: '',
cost: ''
})
const createOrder = () => {
axios
.post("http://localhost:5000/orders", order)
.then(res => {window.location.reload(false)})
.catch(err => console.error(err));
}
const item1 = items[0];
const item2 = items[1];
const item3 = items[2];
const item4 = items[3];
const item5 = items[4];
const item6 = items[5];
return (
<div className="Mid_Container">
<button
style={{backgroundImage: `url(${item1.image})`}}
value={order.item=item1.item,order.cost=item1.price}
onClick={createOrder}
>
<p id="pPrice">${item1.price}</p>
<p id="pItem" >{item1.item}</p>
</button>
<button
style={{backgroundImage: `url(${item2.image})`}}
value={order.item=item2.item,order.cost=item2.price}
onClick={createOrder}
>
<p id="pPrice">${item2.price}</p>
<p id="pItem" >{item2.item}</p>
</button>
<button
style={{backgroundImage: `url(${item3.image})`}}
value={order.item=item3.item,order.cost=item3.price}
onClick={createOrder}
>
<p id="pPrice">${item3.price}</p>
<p id="pItem" >{item3.item}</p>
</button>
<button
style={{backgroundImage: `url(${item4.image})`}}
value={order.item=item4.item,order.cost=item4.price}
onClick={createOrder}
>
<p id="pPrice">${item4.price}</p>
<p id="pItem" >{item4.item}</p>
</button>
</div>
)
}
export default Mid_Container
I think that you should have this approach:
function SomeComponent() {
// Mocking your datas
const [items, setItems] = React.useState([
{
price: "1",
item: "i am the first",
image: "image1.png",
},
{
price: "7",
item: "I am the second",
image: "image2.png",
},
{
price: "3",
item: "i am the third",
image: "image3.png",
},
]);
const [order, setOrder] = React.useState();
const [myResponse, setMyResponse] = React.useState();
const createOrder = (clickedItem) => {
setOrder(clickedItem);
console.log(clickedItem);
// axios
// .post("http://somewhere", clickedItem)
// .then((res) => {
// setMyResponse(res); // or setMyResponse(res.json());
// })
// .catch((err) => console.error(err));
};
console.log('Log selected order in render loop ==> ', order);
console.log('Log response in render loop ==> ', myResponse);
return (
<div>
<div className="Mid_Container">
{items.length && items.map((currItem, index) => {
return (
<button
key={index}
style={{ backgroundImage: `url(${currItem.image})` }}
onClick={() => createOrder(currItem)}
>
<p id="pPrice">${currItem.price}</p>
<p id="pItem">{currItem.item}</p>
</button>
);
})}
</div>
</div>
);
}
Mapping on your items with map function, and pass the current item to your onClickEvent.
I also think you don't need a value attribute on your buttons. It's also not the place to do operations like you do :)
You also don't have to reload the page in the "then" of your promise. React is made to do SPA (single page application), so in the "then", you can put some code like "setResult(myResponse)" to store in you component the new data you got from your API.

Filtering node.js (express, mongoose) app

I am trying to a node.js application (express, mongoose) and I want to give the option to the user to filter the data they receive through checkboxes. In the front end I store the user's choice in cookies (I do not know know if there is a better way) but I failed to filter the data in my database. The html code is that:
A modal that gives the user the option to check for specific data
<div id="modal">
<div id="modalContent">
<h3>Filters</h3><svg xmlns='http://www.w3.org/2000/svg' id="closeBtn" class='ionicon' viewBox='0 0 512 512'><title>Close</title><path fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='32' d='M368 368L144 144M368 144L144 368'/></svg>
<div>
<form method="GET">
<div>
<input type="checkbox" class="save-cb-state" name="Vasilopoulos" value="Vasilopoulos">Vasilopoulos
</div>
<div>
<input type="checkbox" class="save-cb-state" name="Masoutis" value="Masoutis">Masoutis
</div>
<div>
<input type="checkbox" class="save-cb-state" name="Web Only" value="Web Only">Web Only
</div>
<div>
<input type="checkbox" class="save-cb-state" name="In Store" value="In Store">In Store
</div>
<button type="submit">Αναζήτηση</button>
</form>
</div>
</div>
</div>
My model is that:
The checkboxes are filtering for storeName and/or offerType (The problem is when the user wants to filter both data)
const mongoose = require("mongoose");
const offersSchema = new mongoose.Schema({
imgLink: String,
title: String,
startPrice: Number,
discountPrice: Number,
pageLink: String,
storeName: String,
offerType: String,
discountPercentage: {
type: String,
trim: true
}
});
module.exports = mongoose.model("Offers", offersSchema);
The first two checkboxes are referring to StoreName attribute of my model and the last two are referring to offerType
The code in my controller is this:
async function getOffers(req) {
const cookiesArray = Object.values(req.cookies);
const page = parseInt(req.query.page || 1);
const sort = req.query.sort || "discountPrice";
const itemsPerPage = 10;
let products;
//If cookiesArray length is greater than 0 means that the user has check at least one checkbox
if(cookiesArray.length !== 0) {
products = await Offers.find({ offerType: { $in: cookiesArray}, storeName: { $in: cookiesArray } })
.skip((page - 1) * itemsPerPage)
.limit(itemsPerPage)
.sort(sort);
} else {
products = await Offers.find()
.skip((page - 1) * itemsPerPage)
.limit(itemsPerPage)
.sort(sort);
}
return {
category: "offers",
products,
sort,
currentPage: page,
hasNextPage: itemsPerPage * page < totalProducts,
hasPreviousPage: page > 1,
nextPage: page + 1,
previousPage: page - 1,
lastPage: Math.ceil(totalProducts / itemsPerPage)
}
}
getOffers is a helper function that my controller uses to fetch data. I tried to use the in operator but if the user check one or two values from the first two checkboxes and one or two values from the last two check boxes the in operator fails.

Selecting first element from the dropdown [ select tag ] cause the backend to crash but selecting other works just fine

I'm building a simple app with node.js and reactjs but the problem arises when I want to add book especially while selecting dropdown value.
In the select tag when I select the first element it crashes the backend but when I select the second or below it they work just fine. What could be the reason behind it ? Dropdown menu has been filled correctly. My code is :
import React, { Component } from 'react'
import axios from 'axios'
export default class AddBook extends Component {
state = {
name : '',
author : '',
publishers : '',
pages :'',
genres : [],
genre : '',
addedMessage : null
}
async componentDidMount() {
const genres = await axios.get('http://localhost:5000/api/genres')
this.setState({ genres : genres.data})
}
onInputChange = (e) => {
this.setState({[e.target.name] : e.target.value }) //looks for name
}
onFormSubmit = (e) => {
e.preventDefault();
const book = {
name : this.state.name,
author : this.state.author,
publishers : this.state.publishers,
pages : this.state.pages,
genres : this.state.genre
}
axios.post('http://localhost:5000/api/books', book)
.then(res => console.log(res))
.catch(err => console.log("error occured while posting data ", err))
console.log(book)
//alert("book added successfully !!!")
this.setState({addedMessage : 'Book added successfully'})
window.location = "/books"
}
render() {
const { name, author, publishers, pages, genres, addedMessage } = this.state;
return (
<div className="container">
<h2>ADD BOOK </h2>
{ addedMessage && <h2 style={{textAlign : 'center'}} className="alert alert-info">{addedMessage}</h2> }
<form onSubmit = { this.onFormSubmit }>
<div className="form-group">
<label htmlFor="name">BookName:</label>
<input type="text" required className="form-control" id="name"
placeholder="Enter Book name" name="name"
onChange={this.onInputChange}
value={name}
/>
</div>
<div className="form-group">
<label htmlFor="author">Author:</label>
<input type="text" required={ true } className="form-control"
id="author" placeholder="Enter Author" name="author"
onChange={this.onInputChange}
value={author}
/>
</div>
<div className="form-group">
<label htmlFor="publishers">Publishers:</label>
<input type="text" required className="form-control"
id="publishers" placeholder="Enter Publishers Name"
name="publishers"
onChange={this.onInputChange}
value={publishers}
/>
</div>
<div className="form-group">
<label htmlFor="pages">Pages:</label>
<input type="number" required className="form-control"
id="pages" placeholder="Enter No of Page" name="pages"
onChange={this.onInputChange}
value={pages}
/>
</div>
<div className="form-group">
<label htmlFor="genre">Category:</label>
<select type="select" className="form-control"
id="genre"
name="genre"
onChange={this.onInputChange}
>
{/* <option value="selectCategory" onChange={this.onInputChange}>Select</option> */}
{
genres.map( genre => (
<option key={genre._id} onChange={this.onInputChange} value={genre.name}>
{genre.name }</option>
))
}
</select>
</div>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
</div>
)
}
}
My backend is up and running and has successfully fetched the genres[ categories ] , but I am not able
to figure out why selecting the first doesn't work but others just work fine. How should I solve it ?
It shows the following error for this case.
Error: Book validation failed: genres: Path `genres` is required.
at ValidationError.inspect
(E:\nodejs\nodejs\MERN_STACK_Book\node_modules\mongoose\lib\error\validation.js:48:26)
at formatValue (internal/util/inspect.js:718:31)
at inspect (internal/util/inspect.js:287:10)
at afterInspector (internal/errors.js:682:14) {
errors: {
genres: ValidatorError: Path `genres` is required.
at validate (E:\nodejs\nodejs\MERN_STACK_Book\node_modules\mongoose\lib\schematype.js:1178:13)
at E:\nodejs\nodejs\MERN_STACK_Book\node_modules\mongoose\lib\schematype.js:1161:7
at Array.forEach (<anonymous>)
at SchemaString.SchemaType.doValidate
(E:\nodejs\nodejs\MERN_STACK_Book\node_modules\mongoose\lib\schematype.js:1106:14)
at E:\nodejs\nodejs\MERN_STACK_Book\node_modules\mongoose\lib\document.js:2387:18
at processTicksAndRejections (internal/process/task_queues.js:79:11) {
properties: [Object],
kind: 'required',
path: 'genres',
value: '',
reason: undefined,
[Symbol(mongoose:validatorError)]: true
}
},
_message: 'Book validation failed'
}
[nodemon] app crashed - waiting for file changes before starting...
And code for my book schema is as follows
const mongoose = require('mongoose')
//schema for genres
const bookSchema = mongoose.Schema({
name : {
type : String,
required : true,
trim : true,
unique : true //title is made unique.
},
author : {
type : String,
required : true,
trim : true
},
publishers : {
type : String,
trim : true,
},
pages : {
type : Number,
required : true,
trim : true
},
genres : {
type : String,
required : true,
trim : true
},
create_date : {
type : Date,
default : Date.now
}
})
//It will create books collection in your database and documents
//inside that collection will have fields from bookSchema when you save first document.
const Book = module.exports = mongoose.model('Book', bookSchema)
//get the books
module.exports.getBooks = (callback, limit) => {
// Book.find(callback)
Book.find(callback).limit(limit)
}
//get single book
module.exports.getBookById = (id,callback) => {
// Book.find(callback)
Book.findById(id,callback);
}
module.exports.addBook = (book,callback) => {
Book.create(book, callback);
}
module.exports.updateBook = (id,book,options, callback) => {
const query = {
_id : id
}
const updatedBook = {
name : book.name,
author : book.author,
publishers : book.publishers,
pages : book.pages,
genres : book.genres
}
Book.findByIdAndUpdate(query, updatedBook, {} , callback);
}
module.exports.deleteBook = (id,callback) => {
const query = {
_id : id
}
Book.findByIdAndDelete(query, callback);
}
I checked some of the similar answers in the stackoverflow but couldn't figure out why I'm getting that
error.
Here's the problem with your code :
The first option of the dropdown is chosen by default, and thus "selecting" the first option doesn't trigger the Category dropdown's onChange function (because the selected value doesn't really change).
Since the default value of this.state.genre is an empty string, the genres property of the book you send to the backend also has genres as an empty string.
Finally, Mongoose does not accept an empty string for a required string field, which gives you the Path 'genres' is required error.
Try switching to another option and back to the first. It will work then because the onChange function will then get called and this.state.genre will be set properly.
There are a few ways to fix this:
Add a placeholder option to the dropdown - something like "Select an option...". Then the user will be forced to select a genre from the dropdown and onChange would be called.
Or, in componentDidMount, set this.state.genre to the first genre of the list of genres you fetch.

Knockout two way binding not working with Sharepoint modal dialog

I'm trying two way binding (knockout observables) with sharepoint modal dialog
var ViewModel = function () {
var self = this;
self.firstName = "Irfanullah";
self.lastName = ko.observable('M.');
self.fullName = ko.computed(function () {
return self.firstName + ' ' + self.lastName();
});
};
ko.applyBindings(new ViewModel());
<button type=button onclick="openDialog2()">click me</button>
<div id="wrap" style="display:none">
<div id="d10" class="dialogHolder">
<div id="kobasic">
<h4>Editable data</h4>
<p><input type="text" data-bind="value: firstName" /></p>
<p><input type="text" data-bind="value: lastName" /></p>
<p>Full Name: <span data-bind="text: fullName"></span></p>
</div>
</div>
When i test this code on sharepoint wiki page its working good, but when i use same code on sharepoint dialog it shows values (one way binding)but two way binding/ko.observable() does not work (when i type something in lastname text box it does not update fullname)
function openDialog2() {
var e = document.getElementById('d10');
var options = {
title: "Test Knockout",
width: 700,
height: 800,
html: e.cloneNode(true)
};
mydialog = SP.UI.ModalDialog.showModalDialog(options);
}
I believe that is alll becase e.cloneNode(true) but i could not figureout alternat solution
For SharePoint dialogs I am using this approach:
(note: jQuery needed)
// create dom element
var element = document.createElement('div');
// apply my custom view
$(element).append('<!--my HTML -->');
// apply knockout bindings
ko.applyBindings(myViewModel, element);
// show sharepoint modal dialog
var options = {
allowMaximize: false,
html: element,
title: "My title",
autoSize: true,
showClose: true,
dialogReturnValueCallback: myCallback
};
SP.UI.ModalDialog.showModalDialog(options);
So in your case:
var element = document.createElement('div');
$(element).append('<div id="d10" class="dialogHolder"><div id="kobasic"><h4>Editable data</h4><p><input type="text" data-bind="value: firstName" /></p><p><input type="text" data-bind="value: lastName" /></p><p>Full Name: <span data-bind="text: fullName"></span></p></div></div>');
ko.applyBindings(new ViewModel(), element);
var options = {
allowMaximize: false,
html: element,
title: "My title",
autoSize: true,
showClose: true,
dialogReturnValueCallback: myCallback
};
SP.UI.ModalDialog.showModalDialog(options);

Unobtrusive validation with Jquery Steps Wizard

Recently I asked a question for how to customize the JQuery Steps as I wanted to use partial views instead of static content. I have partially solved that problem by using the following code supported by jquery-steps,
<h3>Step 1</h3>
<section data-mode="async" data-url="/Formation/RenderStep1"></section>
<h3>Step 2</h3>
<section data-mode="async" data-url="/Formation/RenderStep2"></section>
Now the big problem I am facing right now is how to use unobtrusive validation. I don't want to use JQuery custom validation and there must be some way of using Obtrusive with it.
Each partial view that is rendered has its own form. I want to validate the form in the onStepChanging function of jquery-steps,
$("#my-steps").steps({
headerTag: "h3",
bodyTag: "section",
contentMode: "async",
transitionEffect: "fade",
stepsOrientation: "vertical",
onStepChanging: function (event, currentIndex, newIndex) {
return true;
}
});
I have tried calling $.validator.unobtrusvie.parse('#myform'); in the onStepChanging function but ('#myform') is undefined and still I don't know that whether this is the right way to call the unobtrusive validation manually. Kindly guide me and show me the direction to achieve this. Any help will be highly appreciated.
It sounds like your trying manage multiple forms within the JQuery Steps library and I don't think that is what its intended for.
When you configure JQuery Steps, you set it up against the form in your view.
Unobtrusive JQuery Validation is looking at the model in your view and automatically configuring the HTML with the relevant data attributes for error handling.
This validation should be firing at the client side automatically.
There shouldn't be a problem with using Partial View's, as long as there encapsulated within the same form element.
What is the requirement to have each partial view wrapped in its own form? If your trying to make multiple posts throughout the JQuery Steps form wizard, your defeating the object.
At each step in the JQuery Steps form, your only validating the one form like this :-
onStepChanging: function (event, currentIndex, newIndex) {
//Allways allow user to move backwards.
if (currentIndex > newIndex) {
return true;
}
// Remove the validation errors from the next step, incase user has previously visited it.
var form = $(this);
if (currentIndex < newIndex) {
// remove error styles
$(".body:eq(" + newIndex + ") label.error", form).remove();
$(".body:eq(" + newIndex + ") .error", form).removeClass("error");
}
//disable validation on fields that are disabled or hidden.
form.validate().settings.ignore = ":disabled,:hidden";
return form.valid();
}
Once the user has finished entering data, and the client side validation has been met, you hook into the onFinished method and post the form :-
onFinished: function (event, currentIndex) {
var form = $(this);
form.submit();
}
The purpose of JQuery Steps is to allow the user to have a fluid experience of filling out a form and to not be overwhelmed with the number of questions been asked.
From the developers perspective, it enables us to split up the form into nice size-able chunks without having to worry about saving progress between screens or losing the state of the form data and allows us to capture all of the required data with only having to make that one post once all validation criteria has been met.
I tried the formvalidation plugin, it will relax your mind from searching in validation without form tag or validation without submit the form that's the issue I solved when I tried it.
I know it's not free but you can try it from here, personally I like it
First update height after validation
<style type="text/css">
/* Adjust the height of section */
#profileForm .content {
min-height: 100px;
}
#profileForm .content > .body {
width: 100%;
height: auto;
padding: 15px;
position: relative;
}
Second, add data-steps index to your section*
<form id="profileForm" method="post" class="form-horizontal">
<h2>Account</h2>
<section data-step="0">
<div class="form-group">
<label class="col-xs-3 control-label">Username</label>
<div class="col-xs-5">
<input type="text" class="form-control" name="username" />
</div>
</div>
<div class="form-group">
<label class="col-xs-3 control-label">Email</label>
<div class="col-xs-5">
<input type="text" class="form-control" name="email" />
</div>
</div>
<div class="form-group">
<label class="col-xs-3 control-label">Password</label>
<div class="col-xs-5">
<input type="password" class="form-control" name="password" />
</div>
</div>
<div class="form-group">
<label class="col-xs-3 control-label">Retype password</label>
<div class="col-xs-5">
<input type="password" class="form-control" name="confirmPassword" />
</div>
</div>
</section>
Third, javascript code
<script>
## // to adjust step height to fit frame after showing validation messages##
$(document).ready(function() {
function adjustIframeHeight() {
var $body = $('body'),
$iframe = $body.data('iframe.fv');
if ($iframe) {
// Adjust the height of iframe
$iframe.height($body.height());
}
}
// IMPORTANT: You must call .steps() before calling .formValidation()
$('#profileForm')
// setps setup
.steps({
headerTag: 'h2',
bodyTag: 'section',
onStepChanged: function(e, currentIndex, priorIndex) {
// You don't need to care about it
// It is for the specific demo
adjustIframeHeight();
},
// Triggered when clicking the Previous/Next buttons
// to apply validation to your section
onStepChanging: function(e, currentIndex, newIndex) {
var fv = $('#profileForm').data('formValidation'), // FormValidation instance
// The current step container
$container = $('#profileForm').find('section[data-step="' + currentIndex +'"]');
// Validate the container
fv.validateContainer($container);
var isValidStep = fv.isValidContainer($container);
if (isValidStep === false || isValidStep === null) {
// Do not jump to the next step
return false;
}
return true;
},
// Triggered when clicking the Finish button
onFinishing: function(e, currentIndex) {
var fv = $('#profileForm').data('formValidation'),
$container = $('#profileForm').find('section[data-step="' + currentIndex +'"]');
// Validate the last step container
fv.validateContainer($container);
var isValidStep = fv.isValidContainer($container);
if (isValidStep === false || isValidStep === null) {
return false;
}
return true;
},
onFinished: function(e, currentIndex) {
// Uncomment the following line to submit the form using the defaultSubmit() method
// $('#profileForm').formValidation('defaultSubmit');
// For testing purpose
$('#welcomeModal').modal();
}
})
.formValidation({
framework: 'bootstrap',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
// This option will not ignore invisible fields which belong to inactive panels
excluded: ':disabled',
fields: {
username: {
validators: {
notEmpty: {
// for asp.net i used element attribute to integerated with unobtrusive validation
// message :$('username').attr('data-val-required')
message: 'The username is required'
},
stringLength: {
min: 6,
max: 30,
message: 'The username must be more than 6 and less than 30 characters long'
},
regexp: {
regexp: /^[a-zA-Z0-9_\.]+$/,
message: 'The username can only consist of alphabetical, number, dot and underscore'
}
}
},
email: {
validators: {
notEmpty: {
message: 'The email address is required'
},
emailAddress: {
message: 'The input is not a valid email address'
}
}
},
password: {
validators: {
notEmpty: {
message: 'The password is required'
},
different: {
field: 'username',
message: 'The password cannot be the same as username'
}
}
},
confirmPassword: {
validators: {
notEmpty: {
message: 'The confirm password is required'
},
identical: {
field: 'password',
message: 'The confirm password must be the same as original one'
}
}
}
}
});

Resources