JQuery Cascade plugin to remember last selected state - javascript

I'm using the JQuery cascade plugin (here)
I have it so I can select a book section in the first dropdown, which populates with chapters in the second drop down. e.g:
var list1 = [
{'When':'0','Value':'0','Text':'Chapter 1'},
{'When':'0','Value':'1','Text':'Chapter 2'},
{'When':'0','Value':'2','Text':'Chapter 3'},
...(snip..)
{'When':'1','Value':'0','Text':'Appendix 1'},
{'When':'1','Value':'1','Text':'Appendix 2'},
{'When':'1','Value':'2','Text':'Appendix 3'},
....(snip..)
];
function commonTemplate(item){
return "<option value='" + item.Value + "'>" + item.Text + "</option>";
};
function commonTemplate2(item) {
return "<option value='" + item.Value + "'>***" + item.Text + "***</option>";
};
function commonMatch(selectedValue) {
return this.When == selectedValue;
};
Which is then called by:
jQuery(document).ready(function()
{
jQuery("#section").cascade("#chapter",{
list: list1,
template: commonTemplate,
match: commonMatch
});
});
my form is pre-populated with section0 and it's associated chapters. Everything works fine - when I select book 2, the script fires and populates the second drop down with the chapters from book 2 etc.
My problem is: When I select a book like "Section 2, Chapter 3", I would like that book and chapter to load while the form on the page displays "Section 2, Chapter 3". This way the user can quickly go to chapter 4 or whatever. Currently, when Section 2, Chapter 3 loads, the form defaults to "Section 1, Chapter 1" which is the default form value from the first time the user arrived at the page.
My Question is: How can I have a default value the first time, but when a user submits the form, the page reloads remembering the last selected section/chapter in the form?
Thanks.

Related

How to fully create HTML from a js object?

I am working on finding a way to use javascript to create blog posts for my website. I am quite knowledgeable in javascript, however I haven't used many DOM elements other than document.getElementById(). I am looking for support in how to implement a way to turn a JS object into a post. Here is an example object:
var posts = { //My object
firstPost: { //An example post
index: 1, //Identifies order of posts: 1 is oldest... >1 newest
id: "first", //An id for the post
date: { //Date will be listed next to name on post
month: 11,
day: 2,
year: 2018
},
name: "My Post", //Name of the post
text: "Text for the post...", //Actual Post
image: 'blogImage.png' //An image for the post
}
And now I want to pass it through a function as shown below to create HTML:
function assemblePost( index, id, month, day, year, text, image) {
//DOM GOES IN HERE
}
Here is an example of how the HTML looks when I type it manually:
<div class="card" id="first"> <!-- Card element links to css -->
<h2>My Post</h2> <!-- Name of the post -->
<h5>Posted November 2nd, 2018</h5> <!-- Date of the post -->
<div class="img" style="height:200px;"><img src="/blogImage.png" ></div>
<p>Text for the post..."</p> <!-- Actual Post -->
</div>
I am not entirely sure how to approach this because:
The class, "card", links to the CSS, and I am not sure how to implement that with DOM.
I am not sure if DOM can edit style, as in this example, the image height is 200, but in another image it could be different.
For many of my other posts, I may have multiple paragraphs and/or lists. At the very least, I wanted a way to create one string of text. Maybe for lists, an array would be most useful in my object, however I am unsure how to address multiple paragraphs.
I realize it is a lot of explaining, examples, and guidelines, but I really do appreciate your help! Thank you!
Just do it step by step.
var posts = [ //My object (array of posts)
{ //An example post
index: 1, //Identifies order of posts: 1 is oldest... >1 newest
id: "first", //An id for the post
date: { //Date will be listed next to name on post
month: 11,
day: 2,
year: 2018
},
name: "My Post", //Name of the post
text: "Text for the post...", //Actual Post
image: 'blogImage.png' //An image for the post
},
{ //An example post
index: 2, //Identifies order of posts: 1 is oldest... >1 newest
id: "first", //An id for the post
date: { //Date will be listed next to name on post
month: 11,
day: 2,
year: 2018
},
name: "My another Post", //Name of the post
text: "Text for another post...", //Actual Post
image: 'blogImage.png' //An image for the post
}
];
const container = document.getElementById('div-posts');
posts.forEach(function(post) {
let div = document.createElement('div');
div.className = 'card';
div.id = 'post_' + post.index; //or post.id provided itis unique
//create more elements instead of ".innerHTML" if you wish
div.innerHTML = '<h2>' + post.name + '</h2>' +
'<h5>' + (new Date(post.date.year, post.date.month, post.date.day).toDateString()) + '</h5>' +
'<div class="img"><img src="/' + post.image + '" ></div>' +
'<p>' + post.text + '</p>';
container.appendChild(div);
});
.card {
border: solid 1px #ccc;
width: 400px
}
.img img {
max-width: 100%
}
<div id="div-posts"></div>

jQuery 'change' doesn't show most up-to-date data

I have a jQuery change function that populates a dropdown list of Titles from the user selection of a Site dropdown list
$("#SiteID").on("change", function() {
var titleUrl = '#Url.Content("~/")' + "Form/GetTitles";
var ddlsource = "#SiteID";
$.getJSON(titleUrl, { SiteID: $(ddlsource).val() }, function(data) {
var items = "";
$("#TitleID").empty();
$.each(data, function(i, title) {
items +=
"<option value='" + title.value + "'>" + title.text + "</option>";
});
$("#TitleID").html(items);
});
});
The controller returns JSON object that populates another dropdown list.
public JsonResult GetTitles(int siteId)
{
IEnumerable<Title> titleList;
titleList = repository.Titles
.Where(o => o.SiteID == siteId)
.OrderBy(o => o.Name);
return Json(new SelectList(titleList, "TitleID", "Name"));
}
The markup is:
<select id="SiteID" asp-for="SiteID" asp-items="#Model.SiteList" value="#Model.Site.SiteID" class="form-control"></select>
<select id="TitleID"></select>
The problem is that the controller method is only touched on the FIRST time a selection is made. For example,
The first time SITE 1 is selected, the controller method will return the updated list of Titles corresponding to SITE 1
If SITE 2 is selected from the dropdown, the controller will return the updated list of Titles corresponding to SITE 2
The user adds/deletes Titles in the database corresponding to SITE 1
User returns to the form and selects SITE 1 from the dropdown. The list still shows the results from step 1 above, not the updates from step 3
If I stop debugging and restart, the selection will now show the updates from step 3.
Similar behavior described in jQuery .change() only fires on the first change but I'm hoping for a better solution than to stop using jQuery id's
The JSON response is:
[{"disabled":false,"group":null,"selected":false,"text":"Title2","value":"2"},{"disabled":false,"group":null,"selected":false,"text":"Title3","value":"1002"},{"disabled":false,"group":null,"selected":false,"text":"Title4","value":"2004"},{"disabled":false,"group":null,"selected":false,"text":"Title5","value":"3"},{"disabled":false,"group":null,"selected":false,"text":"Title6","value":"9004"}]
The issue was that the JSON result was being read from cache as #KevinB pointed out. This was fixed by adding the following line within the change function
$.ajaxSetup({ cache: false });

jQuery/JavaScript preventing duplicate appends

seemingly minor issue I'm having with a mock-forum system I'm trying to prototype, as the following array and table function I've created duplicates a forum table the screen due to the appends I've used, and I'm not sure how to go about avoiding this or amending this (I.e, if the user repetitively clicks the forum page, the forum will repetitively generate). I'm still fairly knew to the language, but from what I've found from similar posts, everything I tried to apply hasn't resolved the issue.
var index;
var topics = [
{title: "Football Topics", followers: 280, articles: 5, posts: [
{postId: 101, contents: "Dummy content", author: "Dummy content", replies:[
{replyId: 1, contents: "Dummy content", author: "Dummy content"},
{replyId: 2, contents: "Dummy content", author: "Dummy content"},
{replyId: 3, contents: "Dummy content", author: "Dummy content"}
]},
]}
];
var topicTable = $("<table class='forumTable'><tr><th>Title</th><th>Posts</th><th>Followers</th></tr></table>");
//console test
//console.log(topics);
//Looping all topics in variable "topics"
for (index in topics) {
//console test
console.log(topics[index].title);
var row = $("<tr></tr>");
row.append("<td>" + topics[index].title + "</td>");
row.append("<td>" + topics[index].articles + "</td>");
row.append("<td>" + topics[index].followers + "</td>");
topicOnClick(row, topics[index]);
topicTable.append(row);
}
page.append(topicTable);
Based on what you've given I think there are a couple of options.
Option 1
You say if the use repetitively 'clicks' the forum page implying there's a click handler. You can use .one which executes the function at most on times.
var table = "<table><tr><td>column1</td><td>column2</td></tr></table>";
$('button').one('click', function() {
$('#tableContainer').append(table);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div id="tableContainer">
</div>
<button>add</button>
</body>
Option 2
You could target the container div and use .html() this will allow the function to run on each click but will write over the content so it gives the appearance of only being loaded once.
var table = "<table><tr><td>column 1</td><td>column 2</td></tr></table>";
$('button').on('click', function(){
$('#tableContainer').html(table);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div id="tableContainer">
</div>
<button>add</button>
</body>

is there any way to create a checkbox list through javascript using kendo

I would like to know whether is there a way to program populate my kendo checkbox list like the image below through javascript object/array because most of the online search result are creating a list at html.
sample of output
If you already have the checkbox list rendered, then use MVVM checked binding:
http://demos.telerik.com/kendo-ui/mvvm/elements
http://docs.telerik.com/kendo-ui/framework/mvvm/bindings/checked
If you want to render the checkbox list with JavaScript, according to some data, and check the checkboxes at the same time, then use Kendo UI templates and kendo.render()
http://docs.telerik.com/kendo-ui/framework/templates/overview
http://docs.telerik.com/kendo-ui/api/javascript/kendo#methods-render
<ul id="checkboxList"></ul>
<script>
var template = kendo.template("<li>" +
"<label>" +
"<input type='checkbox' #: isChecked ? \" checked='checked'\" : \"\" # />" +
"#: name #" +
"</label>" +
"</li>");
var data = [
{ id: 1, name: "foo", isChecked: true },
{ id: 2, name: "bar", isChecked: false }
];
var html = kendo.render(template, data);
$("#checkboxList").html(html);
</script>
Instead of kendo.render(), you can alternatively use a Kendo UI ListView and an item template. The template definition itself can be the same.
http://demos.telerik.com/kendo-ui/listview/index
http://docs.telerik.com/kendo-ui/api/javascript/ui/listview#configuration-template

Javascript: If then statement not working in function

I'm building a personality-type quiz and having difficulty tailoring the results page as I'd like it to. The if statement, contained in the display_scenario function, isn't working. I want it to generate a different final message depending on the value of the countValue variable but it's not working. If you are able to help me understand why it's not working, I'd appreciate it.
The key pieces of code are below. It's also in place on Codepen: http://codepen.io/msummers40/pen/eZaePe
Essentially, the quiz:
- asks people a series of questions
- each answer has a numeric weight assigned to it
- this numeric weight is tallied in the countValue variable
- I want to use the countValue variable as a way to generate one of four final pages
I've tried to set up an if statement at the end of the quiz but it's just not working and I'm unsure of how to get this to work - it seems to be building the final view regardless of what's in the if statement.
If you are able to help, thank you.
<body>
<!-- QUIZ BEGINS -->
<div id="wrapper">
<h2 id="cyoaHeader">TITLE HERE<br><small>SUBHED</small></h2>
<div id="quizImage"> </div>
<div id="prompt"> </div>
<div id="options"> </div>
<div id="buildingStatus"> </div>
</div>
<div id="addLinks"> </div>
<!-- QUIZ ENDS -->
<script>
// JSON for quiz
// Contains the questions, images and variable to give answers weight/direction
var story = {
intro: {
prompt: 'You need to get up and out and get on with a big task - what song would propel you out of bed?',
quizImage: '<img id="quizImage" src="https://upload.wikimedia.org/wikipedia/commons/a/ab/Semi-nude_woman_getting_out_of_bed_(rbm-QP301M8-1887-265a~5).jpg"><br />',
options: [{
name: 'Song 4',
path: 'questionTwo',
addition: 4
}, {
name: 'Song 3',
path: 'questionTwo',
addition: 2
}, {
name: 'Song 2',
path: 'questionTwo',
addition: 3
}, {
name: 'Song 1',
path: 'questionTwo',
addition: 1
}]
},
questionTwo: {
prompt: 'Sentence.<br/><br/>Question 2?',
quizImage: '<img id="quizImage" src="http://www.allgifs.com/wp-content/uploads/2013/09/pancake.gif">',
options: [{
name: 'A',
path: 'result',
addition: 4
}, {
name: 'B',
path: 'result',
addition: 3
}, {
name: 'C',
path: 'result',
addition: 2
}, {
name: 'D',
path: 'result',
addition: 1
}]
},
result: {
prompt: 'This is the default statement on the results page. I need to make it tailored to the countValue variable',
quizImage: '<img id="quizImage" src="http://viralgifs.com/wp-content/uploads/2014/03/cat_did_u_forget.gif">',
options: [{
name: 'FINAL CTA',
path: 'intro',
addition: 0
}]
}
};
//establishing counter for weighted answer
var countValue = 0;
console.log(countValue);
var additionInt = 0;
console.log(additionInt);
// Option is an object with properties {name and path objects, addition array}
function display_scenario(options) { //value passed had been chosen_options
var option_name = options.name;
var option_path = options.path;
var additionInt = options.addition;
countValue += additionInt;
// countValue = (additionInt + countValue);
console.log(additionInt);
console.log(countValue);
var scenario = story[option_path];
// Clear the #prompt, #quizImage, #options, #addLinks, #buildingStatus divs before writing new ones in if statment below -- GROUP THESE IN A FUNCTION BEFORE GO LIVE
jQuery('#prompt').empty();
jQuery('#quizImage').empty();
jQuery('#options').empty();
jQuery('#addLinks').empty();
jQuery('#buildingStatus').empty();
// THIS IF ELSE STRUCTURE DOESN'T SEEM TO BE WORKING - I'M TRYING TO SET IT UP SO THAT IT DISPLAYS ONE OF FOUR OPTIONS, DEPENDING ON THE VALUE OF THE countValue VARIABLE. ATM ONLY THREE OPTIONS ARE IN PLACE; NONE ARE WORKING.
// Create a <p> to display what the user has chosen if option_name is not null and append it to the #prompt <div>
if (options.name != 'result') {
jQuery('<p>').html('<i>You selected <b>' + option_name + '</b></i><br><p>And the running total is ' + countValue + '</p>').appendTo('#buildingStatus');
// Append the scenario's prompt
jQuery('<p>').html(scenario.prompt).appendTo('#prompt');
// Appending an image
jQuery('<p>').html(scenario.quizImage).appendTo('#quizImage');
// Appending links in the addLinks div
jQuery('<div>').html(scenario.addLinks).appendTo('#addLinks');
} else if (options.name == 'result' && countValue<17) {
jQuery('<p>').html('<i>Yay! This option worked. You selected <b>' + option_name + '</b></i><br><p>And the running total is ' + countValue + '</p>').appendTo('#buildingStatus');
// Append the scenario's prompt
jQuery('<p>').html(scenario.prompt).appendTo('#prompt');
// Appending an image
jQuery('<p>').html(scenario.quizImage).appendTo('#quizImage');
// Appending links in the addLinks div
jQuery('<div>').html(scenario.addLinks).appendTo('#addLinks');
} else {
jQuery('<p>').html('<i>Yay! This option worked. You selected <b>' + option_name + '</b></i><br><p>And the running total is ' + countValue + '</p>').appendTo('#buildingStatus');
// Append the scenario's prompt
jQuery('<p>').html(scenario.prompt).appendTo('#prompt');
// Appending an image
jQuery('<p>').html(scenario.quizImage).appendTo('#quizImage');
// Appending links in the addLinks div
jQuery('<div>').html(scenario.addLinks).appendTo('#addLinks');
};
// Append the options into the #options <div>
// We want to loop through all the options and create buttons for each one. A regular for-loop would not suffice because adding a button is not asynchronous. We will create an asynchronous loop by using recursion
function add_option_button(index) {
if (index === scenario.options.length) {
// Base case
return;
}
var option = scenario.options[index];
// Create a <button> for this option and append it to the #options <div>
jQuery('<button>')
.html(option.name)
.click(function(e) {
// This is an onclick handler function. It decides what to do after the user has clicked on the button.
// First, prevent any default thing that the button is going to do, since we're specifying our own action for the button
e.preventDefault();
// We'll want to call display_scenario() with this option
display_scenario(option);
})
.appendTo('#options');
// Add the next option button
add_option_button(index + 1);
}
add_option_button(0);
}
// This function waits until the document is ready
jQuery(document).ready(function() {
// Start the quiz
display_scenario({
name: null,
path: 'intro',
addition: 0
});
});
</script>
</body>
</html>
I think you need to recalculate the sum whenever the user changes something, apart from displaying the scenarios everytime. Split the display_scenario function into one to display the options, and into separate logic to sum up all options choosen.

Categories