Create Wizard steps in MVC and Razor - asp.net-mvc-3

I would like to build one MVC application to create the account of a user using more then one wizard steps.
Do I need to go with one view page and hide or display a div by client side logic or do I need to create different view for each wizard (using partial views)?
What is the best option here? I need to maintain state data between wizard steps so the user can move back or next and on last step he or she can save it to the database.

There are different possibilities. You could use a pure client side solution by showing/hiding sections or a full server side solution. It's up to you to decide which one is best for your particular scenario. Here's an example you might take a look at if you decide to go the server side approach.

Depends on if you allow javascript or not.
If you allow javascript, use jQuery to show/hide divs.
I just made the following wizard script. It supports multiple wizards on the same page, as long as you follow the class/div syntax below.
<div class="wizard">
<div class="step active">
some information
</div>
<div class="step" style="display:none">
Step 2 info
</div>
<div class="step" style="display:none">
Step 3 info
</div>
<input type="button" class="prev" style="display: none" value="Previous" />
<input type="button" class="next" value="Next" />
</div>
<script type="text/javascript">
$(function() {
$('.wizard .prev').click(function() {
var wizard = $(this).parent('.wizard');
$('.step.active', wizard).hide();
var currentStep = $('.step.active', wizard);
currentStep.hide();
currentStep.removeClass('active');
var newStep = currentStep.prev('.step', wizard);
newStep.addClass('active');
newStep.show();
if ($('.step:first', wizard)[0] == newStep[0]) {
$(this).hide();
}
$('.next', wizard).show();
});
$('.wizard .next').click(function() {
var wizard = $(this).parent('.wizard');
$('.step.active', wizard).hide();
var currentStep = $('.step.active', wizard);
currentStep.hide();
currentStep.removeClass('active');
var newStep = currentStep.next('.step', wizard);
newStep.addClass('active');
newStep.show();
if ($('.step:last', wizard)[0] == newStep[0]) {
$(this).hide();
}
$('.prev', wizard).show();
});
});
</script>
Without javascript:
Create a view model which contains information for all steps and share it between all wizard step views. This allows you to keep all state between the different POSTs.

I'm doing something similar at the moment. I'm collecting a large set of data over several steps and allowing the users to save the data at any point.
I've basically split it up into multiple views and created ViewModels for each view with the relevant info for that wizard step. Seems to be working reasonably well for my purposes.

Related

Scripts not working on partial view after Ajax call

I have called scripts on _Layout.cshtml page and my Index.cshtml page has partial view into it. So on page load, SignalR scripts working perfect on partial view, on page end I make another ajax request and load the partial view with another data filled in that and embed under already displayed data, and then the SignalR does not work on the newly embedded record.
This is my index page code:
<div class="col-md-6">
<div class="profile-body">
<div class="row infinite-scroll">
#Html.Partial("_AlbumRow", Model)
</div>
</div>
</div>
This is my partial View Code:
#model IEnumerable<SmartKids.Lib.Core.ViewModels.FileMediaAlbumsVM>
#foreach (var item in Model)
{
<div class="widget">
<div class="block rounded">
<img src="#Url.Content(item.ImageUrl)" alt="#item.Title">
<input type="button" data-image-id="#item.imageId" class="btn btn-sm btn-default">Like</input>
</div>
</div>
}
Kindly help me how to resolve this issue that after making an ajax request I am not able to get those SignalR working. Here is more to say when I put the SignalR scripts on PartialView that works but it also sucks that on each ajax request there is again SignalR loaded on the page and when I click on LIke button it makes many calls to the function behind it.
Kindly help me to resolve this issue, I am stuck at this point since 1 week.
Here is signalR Code:
$(".btn.btn-sm.btn-default").on("click", function () {
var imageId = $(this).attr("data-image-id");
albumClient.server.like(imageId);
});
Problem: You are binding event to elements directly, So when you remove this element and replace it with a different one the events are also removed along with that element, This is something like strongly coupled.
Solution: Use Jquery event delegation. This will make sure the events will be triggered on the current elements and also all the elements that can come in future.
syntax is as below.
$(document).on("click", ".btn.btn-sm.btn-default",function () {
var imageId = $(this).attr("data-image-id");
albumClient.server.like(iamgeId);
});
NOTE: This was never a singlaR issue, it was Jquery issue.
Efficient Way: The problem in using $(document).on("click"... is that when ever there is a click happening on the entire page the Jquery framework will bubble the events from the clicked element upwards(its parent, and its parent and so on..) unless the element specified in the selector arrives, So its kind of performance hit as we don't want this check's to run if we are clicking outside the required area ( button .btn.btn-sm.btn-default in this example).
So best practice is to bind this event delegation to the closest parent possible which will not be removed, <div class="row infinite-scroll"> in this question. So that only when the click happens within this element the event bubbling will happen and also will be stopped once it reaches the parent element,it acts kind of a boundary for event bubbling.
$('.row.infinite-scroll').on("click", ".btn.btn-sm.btn-default",function () {
var imageId = $(this).attr("data-image-id");
albumClient.server.like(iamgeId);
});

Form select box in Backbone Marionette

I'm trying using Backbone.Marionette to build an application. The application gets its data through REST calls.
In this application I created a model which contains the following fields:
id
name
language
type
I also created an ItemView that contains a complete form for the model. The template I'm using is this:
<form>
<input id="model-id" class="uneditable-input" name="id" type="text" value="{{id}}"/>
<input id="model-name" class="uneditable-input" name="name" type="text" value="{{name}}" />
<select id="model-language" name="language"></select>
<select id="model-type" name="type"></select>
<button class="btn btn-submit">Save</button>
</form>
(I'm using Twig.js for rendering the templates)
I am able to succesfully fetch a model's data and display the view.
What I want to do now is populate the select boxes for model-language and model-type with options. Language and type fields are to be restricted to values as a result from REST calls as well, i.e. I have a list of languages and a list of types provided to me through REST.
I'm contemplating on having two collections, one for language and one for type, create a view for each (i.e. viewLanguageSelectOptions and viewTypeSelectOptions), which renders the options in the form of the template I specified above. What I am not sure of is if this is possible, or where to do the populating of options and how to set the selected option based on data from the model. It's not clear to me, even by looking at examples and docs available, which Marionette view type this may best be realized with. Maybe I'm looking in the wrong direction.
In other words, I'm stuck right now and I'm wondering of any of you fellow Backbone Marionette users have suggestions or solutions. Hope you can help!
Create a view for a Select in my opinion is not needed in the scenario that you are describing, as Im assuming that your languages list will not be changing often, and the only porpouse is to provide a list from where to pick a value so you can populate your selects in the onRender or initializace function of your view using jquery.
you can make the calls to your REST service and get the lists before rendering your view and pass this list to the view as options and populate your selects on the onRender function
var MyItemView = Backbone.Marionette.ItemView.extend({
initialize : function (options) {
this.languages = options.languages;
this.typeList = options.typeList;
},
template : "#atemplate",
onRender : function () {
this.renderSelect(this.languages, "#languagesSelect", "valueofThelist");
this.renderSelect(this.typeList, "#typesSelect", "valueofThelist")
},
renderSelect :function (list, element, value) {
$.each(list, function(){
_this.$el.find(element).append("<option value='"+this[value]+"'>"+this[value]+"</option>");
});
}
})
var languagesList = getLanguages();
var typeList = getTypesList();
var myItemView = new MyItemView({languages:languagesList,typeList :typeList });
Hope this helps.

How to update a label from a postback in MVC3/Razor

MVC/Razor/Javascript newbie question:
I have a MVC3/Razor form where the use can select a single product from a drop down list.
<div class="editor-label">
Product
</div>
<div class="editor-field">
#Html.DropDownList("ProductID", (IEnumerable<SelectListItem>)ViewBag.Products, "--Select One--")
#Html.ValidationMessageFor(model => model.ProductID)
</div>
What I then want is to display the price of the selected product on a label just below the drop down list (model property name is Amount).
This should be pretty easy, but I am pretty new at Razor, and know almost nothing about Javascript, so I would appreciate any verbose explanations of how do do it, and how it all hangs together.
Add a div/span under the Dropdown .
#Html.DropDownList("ProductID", (IEnumerable<SelectListItem>)ViewBag.Products, "--Select One--")
<div id="itemPrice"></div>
and in your Script, make an ajax call to one of your controller action where you return the price.
$(function(){
$("#ProductId").change(function(){
var val=$(this).val();
$("#itemPrice").load("#Url.Action("GetPrice","Product")", { itemId : val });
});
});
and have a controller action like this in your Product controller
public string GetPrice(int itemId)
{
decimal itemPrice=0.0M;
//using the Id, get the price of the product from your data layer and set that to itemPrice variable.
return itemPrice.ToString();
}
That is it ! Make sure you have jQuery loaded in your page and this will work fine.
EDIT : Include this line in your page to load jQuery library ( If it is not already loaded),
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
The Amount isn't available to your view when the user selects a product (remember the page is rendered on the server, but actually executes on the client; your model isn't available in the page on the client-side). So you would either have to render in a JavaScript array that contains a lookup of the amount based on the product which gets passed down to the client (so it's available via client-side JavaScript), or you would have to make a callback to the server to retrieve this information.
I would use jQuery to do this.
Here's a simple example of what the jQuery/Javascript code might look like if you used an array.
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
$(document).ready(function() {
// This code can easily be built up server side as a string, then
// embedded here using #Html.Raw(Model.NameOfPropertyWithString)
var list = new Array();
list[0] = "";
list[1] = "$1.00";
list[2] = "$1.25";
$("#ProductID").change(displayAmount).keypress(displayAmount);
function displayAmount() {
var amount = list[($(this).prop('selectedIndex'))];
$("#amount").html(amount);
}
});
</script>
<select id="ProductID" name="ProductID">
<option value="" selected>-- Select --</option>
<option value="1">First</option>
<option value="2">Second</option>
</select>
<div id="amount"></div>
You'll want to spend some time looking at the docs for jQuery. You'll end up using it quite a bit. The code basically "selects" the dropdown and attaches handlers to the change and keypress events. When they fire, it calls the displayAmount function. displayAmount() retrieves the selected index, then grabs the value out of the list. Finally it sets the HTML to the amount retrieved.
Instead of the local array, you could call your controller. You would create an action (method) on your controller that returned the value as a JsonResult. You would do a callback using jquery.ajax(). Do some searching here and the jQuery site, I'm sure you'll find a ton of examples on how to do this.

JQuery for Push-down form

Is there a JQuery plugin that allows me to 'unhide' a form by after clicking a link? Like I have an invite link that can take me to a one text field form for an email address but I want this form to just drop down (pushing the rest of the content down also) and shows the form to submit the email. If you guys can think of a JQuery plugin that lets me do this, please let me know
Edit:
So I did this
<div class='add-link'>
<div id='invite_link'><a href=''>Invite User</a></div>
<div id='invitation_form'>
<form>
<input type='text'/>
</form>
</div>
</div>
and my jquery looks like
<script type="text/javascript">
$(function()
{
$("table").tablesorter({sortList:[[0,0],[2,1]], widgets: ['zebra']});
$('#invitation_form').hide();
}
);
$('#invite_link').click(function() {
$('#invitation_form').slideDown();
});
Do you guys see any error that causes the form not to slide down. It hides the form when the page loads but when I click the link it is not sliding down.
$('a.mylink').click(function() {
$('#MyForm').slideDown();
});
I don't think you need a jQuery plugin for this. The base jQuery library should be sufficient.
$('#showFormLink').click(function () {
$('#form').slideDown();
});
If you're looking for animation, that's possible as well by passing in a duration argument to slideDown.
Take a look at the jQuery show documentation.

Ajax cross domain question

In the code there are two methods, 1st method should read the text from the same domain that is example.com, and the 2nd function should read the text from different domain that Google.com/example.txt. Could any please let me know who to do this. I'm not sure whether I have framed the question properly. Please ask me if you do not understand my question.
//Ajax Question
//The html file path is http://example.com/example.html
<html>
<head>
<script type="text/javascript">
function Click1()
{
var div=// read the text from http://example.com/example.txt
document.getElementById("div1").innerHTML = div;
}
function Click2()
{
var div=// read the text from http://google.com/example.txt
document.getElementById("div2").innerHTML = div;
}
</script>
<body>
<input type="Button" Value="Button 1"name="textbox" onClick="Click1();"/>
<div id="div1">
</div>
<input type="Button" Value="Button 2"name="textbox" onClick="Click2();"/>
<div id="div2">
</div>
This cannot be accomplished using pure scripting technology. One way to achieve it is to write a server side script on example.com that will serve as a bridge to the other domain and perform the ajax call to example.com/bridge.cgi. In case you have control over the other domain you could also use JSONP which doesn't rely on XHR but instead it includes a script tag into the DOM and thus is limited to GET requests only.

Resources