Image Slider in MVC 5 - javascript

I am developing MVC 5 application in which I want to display all related images in time interval of 2 sec. Image path is stored in Database. I know that I can use setInterval javascript function for the same. I am able to loop through first two image (index is hard-coded), however want to display all images one by one
Below is my jquery for the same. Please let me know how i can set index dynamically
$(document).ready(function () {
var curImg = 0;
setInterval(function () {
var path = '#Model.lstImage[1].image_path'
$('#memImg').attr("src",path);
}, 2000);

You need to create a array of image links from your model first and then use it in the set interval. use this logic.
Put this in your view.
#{
var imageLinks = #Model.lstImage.Select(x => x.image_path).ToList();
}
Now we have the list of imageLinks. let use this in Jquery
Add this logic in your script
var imageArray = #Html.Raw(Json.Encode(imageLinks)); // assign the c# variable data into jquery variable.
$(document).ready(function () {
var curImg = 0;
var index = 0;
setInterval(function () {
if(index > imageArray.length){
index = 0; // set back index to zero when the last index is reached.
}
var path = imageArray[index];
$('#memImg').attr("src",path);
index++; //increment the index for next image display.
}, 2000);
});

Note that image paths are available at server-side (in your ViewModel) but switching is made at client side (with setInterval). Now you have (at least) two options:
1) Save whole list in a JavaScript array, setInterval() callback will then simply loop through it.
<script type = "text/javascript">
var currentImage = 0;
var images = #("[" + String.Join(",", Model.lstImage.Select(x =>
String.Format("\"{0}\"", HttpUtility.JavaScriptStringEncode(x.image_path)) + "]");
$(document).ready(function () {
setInterval(function () {
currentImage = (currentImage === images.length - 1) ? 0 : currentImage + 1;
document.getElementById("memImg").src = images[currentImage];
}, 2000);
});
</script>
One note about C# array to JavaScript array: do not use (even if it's widely encouraged, also here on Stack Overflow) Json.Encode(). Escaping rules for JavaScript and for JSON are different, there is a small intersection but a valid JSON string may be not a valid JavaScript string. For example / may be escaped in JSON as \/ but in JavaScript it's an invalid escape sequence (even if most browsers accept it). Think about: http://www.example.com/images/01.png, it doesn't matter what Json.Encode() actually does, it may change its behavior still respecting its interface (encoding an object as valid JSON string...)
2) Do not save image URLs in your ViewModel, just its length. Client side JavaScript code will then query server using (for example): http://www.example.com/images/1 and your controller method will resolve image from its ID and return it with File() or writing directly into response stream.
<script type = "text/javascript">
var currentImage = 0, imageCount = #Model.lstImage.Count;
$(document).ready(function () {
setInterval(function () {
currentImage = (currentImage === imageCount - 1) ? 0 : currentImage + 1;
document.getElementById("memImg").src =
#Url.Action("Read", "Images") + "?id=" + currentImage;
}, 2000);
});
</script>
With this controller method:
public class ImagesController : Controller {
public ActionResult Read(int id) {
return ... // your code here
}
}

Related

Variable scope or return issue (not sure which)

Using the script below I'm attempting to create an object called temptagarray which gets populated with all the tags on a Tumblr weblog and their frequency. So it should end up looking like this:
{'performance': 10, 'installation': 5}
I know the object is being created and it looks correct (I can print it out in each loop) but I can't figure out how to use it after/outside the function i.e. at the bottom of the script where I attempt to document.write() it out. Is this a global/local variable issue, a return issue or do I need to address it in some way?
<script type="text/javascript">
var temptagarray = {};
var tags;
var tag;
function loadPosts () {
var key = "api_key=9I4rZAYQCbU1o5TSMZuyrlvXiQsNxKBicCJxNK5OKZ6G9pgdim";
var api = "https://api.tumblr.com/v2/blog/garrettlynch.tumblr.com/";
var retrieve_more = function (offset) {
$.getJSON(api + "posts?callback=?&filter=image&limit=20&offset=" + offset + "&" + key,function(data) {
//for each item (post) in the response
$.each(data.response.posts, function(i, item) {
//pull out the posts tags
tags = item['tags'];
//loop through the tags
for (i = 0; i < tags.length; i++)
{
tag = tags[i];
//if the tag already exists in the tag array
if (temptagarray[tag])
{
temptagarray[tag] = temptagarray[tag] + 1;
}
else
{
temptagarray[tag] = 1;
}
}
});
if (data.response.posts.length == 20) {
retrieve_more(offset + 20);
}
});
};
retrieve_more(0);
}
loadPosts();
document.write(JSON.stringify(temptagarray));
</script>
Thanks in advance
Garrett
Replace this:
if (data.response.posts.length == 20) {
retrieve_more(offset + 20);
}
...with this:
if (data.response.posts.length == 20) {
retrieve_more(offset + 20);
} else {
document.write(JSON.stringify(temptagarray));
}
The problem you're having is that, despite your document.write(...) command being located below the ajax call in your code, the ajax call is asynchronous and thus the callback will be invoked asynchronously as well. Basically, document.write(...) is being invoked long before you've had a chance to interact with the temptagarray variable in the ajax callback.
First things first - AJAX is Async Asynchronous.
So the code block does not wait for the previous instruction to be completed before it executes the next line.
So your document.writeline would have already been executed by the time the response comes back.
Try printing that info in the success call back after the if block and you would indeed see the response.
thanks for the replies. Below is what I have now as a workable solution as the result is going to call another function anyway. Reading a little bit more I'm wondering if I should be using a callback - is it better?
<script type="text/javascript">
//load posts from a Tumblr weblog
function loadPosts () {
//api key and weblog address
var key = "api_key=9I4rZAYQCbU1o5TSMZuyrlvXiQsNxKBicCJxNK5OKZ6G9pgdim";
var api = "https://api.tumblr.com/v2/blog/garrettlynch.tumblr.com/";
//tags object
var temptagarray = {};
//all tags and each tag
var tags;
var tag;
//looping function to keep retrieving posts until all are retrieved
var retrieve_more = function (offset) {
$.getJSON(api + "posts?callback=?&filter=image&limit=20&offset=" + offset + "&" + key,function(data) {
//for each item (post) in the response
$.each(data.response.posts, function(i, item) {
//pull out the posts tags
tags = item['tags'];
//loop through the tags
for (i = 0; i < tags.length; i++)
{
//pull out each tag
tag = tags[i];
//if the tag already exists in the tag array
if (temptagarray[tag])
{
//add 1 to its count
temptagarray[tag] = temptagarray[tag] + 1;
}
else
{
//set its count to 1
temptagarray[tag] = 1;
}
}
//to test object as it gets added to
//$("#Posts ul").append('<li>' + JSON.stringify(item, ['tags']) + '</li>')
});
//if the number of posts is more than 20
if (data.response.posts.length == 20)
{
//retrieve the next 20
retrieve_more(offset + 20);
}
else
{
//call the show result function
showresult(temptagarray);
}
});
};
//stop retrieving posts
retrieve_more(0);
}
loadPosts();
function showresult(tagarray)
{
$("#Posts ul").append('<li>' + JSON.stringify(tagarray) + '</li>');
//document.write(JSON.stringify(tagarray));
}
</script>

Random order for flash files on page using php, ajax, javascript

I have no experience of Ajax and little experience of java, lots of sql & php experience so I will probably receive lots of comments for this question but here goes.
Ultimately I have 4 flash swf files that needs to be rotated on the website main page randomly. So I've found a shuffle javascript function online and implemented that. Now I need to implement this ajax function (from this post Javascript change inner html of div that conatins php include ) to change the swf files according to the numbers in the array, so if tempArray = 4,3,1,2 then display flash-4.php for 3sec, then change to flash-3.php for 3sec, then change to flash-1.php for 3sec, etc.
I've got the shuffle part working:
<script type="text/javascript">
Array.prototype.shuffle = function() {
var input = this;
for (var i = input.length-1; i >=0; i--) {
var randomIndex = Math.floor(Math.random()*(i+1));
var itemAtIndex = input[randomIndex];
input[randomIndex] = input[i];
input[i] = itemAtIndex;
}
return input;
}
var tempArray = [ 1, 2, 3, 4 ]
tempArray.shuffle();
// and the result is...
alert(tempArray);
//alert(tempArray[0]);
</script>
I've got the ajax part where it's replacing the content working:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script type="text/javascript">
setInterval(function()
{
$.ajax( "flash-2.php" )
.done(function(res) {
document.getElementById("swfdiv").innerHTML = res;
})
},
3000);
</script>
But how do I put it together to rotate depending on the array values?
Why not something like this?
var index = 0;
var tempArray = ...
setInterval(function()
{
index = (index + 1) % tempArray.length;
$.ajax( "flash-" + tempArray[index] + ".php" )
.done(function(res) {
document.getElementById("swfdiv").innerHTML = res;
})
},
3000);

Underscore.js performance issue - Can i use _.defer

In an simple web app that i am building using underscore.js and jquery. For a list of all people ( js object ) I am filtering out list of all the places (js object) they visited. People list is a html table with a td having places image icon which on click displays list of all places they visited. Icon needs to be shown only for people who have visited at the least one place. The problem here is that people and places count comes around 2000, 100. So the code below executes 2000*100 combinations. The browser complains me of unresponsive script. Code is provided below
_.each(peopleList, function (person, index, list) {
//filter the respective places for people
var visitedPlaces = _.filter(places, function (place) {
return place.PeopleId == person.Id;
});
if (_.isEmpty(visitedPlaces)) {
$("a#" + place.PeopleId).remove();
}
});
Dead simple isn't it. For each person check if visited places has him tracked. How do i optimize the above code to unblocking and responsive. Tried putting in _.defer and _.delay at some places but no improvement
FWIW, here is how I would solve it in underscore.
function removeNonTravelers(people, visits) {
var travelers = _.pluck(visits, 'PeopleId'),
nonTravelers = _.reject(people, function (person) {
return _.contains(travelers, person.Id);
});
$(_.map(nonTravelers, document.getElementById)).remove();
}
http://jsfiddle.net/FWzeN/
My suggestion would be to drop underscore and use plain JS for this:
function removeNonTravelers(people, visits) {
var i, peopleId,
numPeople = people.length,
numVisits = visits.length,
index = {}, nonTravelers = [];
// index
for (i = 0; i < numVisits; i++) {
peopleId = visits[i].PeopleId;
if (!index.hasOwnProperty(peopleId)) {
index[peopleId] = 1;
} else {
index[peopleId]++;
}
}
// find HTML elements to remove
for (i = 0; i < numPeople; i++) {
peopleId = people[i].Id;
if (!index.hasOwnProperty(peopleId)) {
nonTravelers.push(document.getElementById(peopleId));
}
}
// remove them all at once
    $(nonTravelers).remove();
}
This is reasonably fast. If I didn't make any mistake, your test case (2000 people, 100 places) times at more than 700 operations per second on my rather outdated laptop (DOM operations excluded).
Try for yourself: http://jsperf.com/where-not-exists-in-javascript
var hashMap = {};
_.each(places, function(place) {
hashMap[place.PeopleId] = place;
});
_.each(peopleList, function (person, index, list) {
//filter the respective project documents
var visitedPlaces = hashMap[person.id];
if (visitedPlaces) {
$("a#" + place.PeopleId).remove();
}
});

Executing Javascript code after loading refreshed page

I have a Javascript file that is split into to two parts. The first part of the code ends by refreshing the current page. I would like to try to get the second part of the code to execute as soon as the page reloads, but I am having trouble finding a way to implement this. I pretty much want a way to do
window.onload = someFunction()
except that it activates the function after reloading the page due to the first part of the Javascript. Is there an effective way to do this?
You could do that using Jquery.
This is executed on page loading
$(function() {
callMyFunction()
});
Use
document.onload = somefunction()
Instead . This will get executed immediately after the DOM loads .
You can also use the jQuery to do the same like
$(document).ready(function(){
somefunction();
});
The only way I can think of is to add query string value when refreshing, then read that value and act upon it.
You can use such code:
function ParseQueryString() {
var result = [];
var strQS = window.location.href;
var index = strQS.indexOf("?");
if (index > 0) {
var temp = strQS.split("?");
var arrData = temp[1].split("&");
for (var i = 0; i < arrData.length; i++) {
temp = arrData[i].split("=");
var key = temp[0];
var value = temp.length > 0 ? temp[1] : "";
result[key] = value;
}
}
return result;
}
window.onload = function WindowLoad() {
var QS = ParseQueryString();
var reloaded = QS["reloaded"];
if (reloaded === "1") {
//execute second part of code
}
}
Then when reloading, redirect to same page adding ?reloaded=1 otherwise (if this flag is already raised) don't refresh the page again to avoid infinite loop.

how do you add a custom callback javascript param to a bing api callback?

The bing V2 javascript api requires a callback to work. Using jQuery to add the script block dynamically (ignoring pollution of global namespace):
function translate(text) {
var txt = "text=" + text;
var lang = "&to=fr";
var appId = "&appid=apikey"; // Add your AppId here
var func = "&oncomplete=window.translated";
$("<script><\/script>")
.attr("src", "http://api.microsofttranslator.com/V2/ajax.svc/Translate?" + txt + lang + appId + func)
.appendTo("HEAD");
}
and then using a click event on multiple elements to trigger the translation:
$(document).ready(function () {
$('a').click(function () {
var tr = $(this).parent().parent();
var txtin = tr.find('.in').text();
var out = tr.find('.out'); // would like translation inserted here
translate(txtin);
return false;
});
});
and finally the callback required by the api:
function translated(text) {
$("#translation").text(text);
}
I want to specify different elements to received the translated text, depending on what element was clicked to kick the translation of - but using the above approach I can't pass any extra params to bing, to then be returned in the callback.
How should I rewrite this to allow a click on el in row1 to put the translation in row1 and a click on an el in row2 to put the translation in row2? i.e. using the element assigned to 'out' in my click event.
The callback method does not support a state object, so you need to keep track of your objects in some global place. I've implemented a queue model to help you make it
Add the queue definition in the global variables are
var queue = new Array();
Add your 'out' object to it just before calling the service
$('a').click(function () {
var tr = $(this).parent().parent();
var txtin = tr.find('.in').text();
var out = tr.find('.out'); // would like translation inserted here
//Here it goes
queue.push(out);
////////////////
translate(txtin);
return false;
});
Append the index of your object to the text and it will be returned back to you as the service does not translate numbers. You can skip adding the index if you are not making more than one translation at a time, this is only to grant that you get the correct object in case of having some service calls slower than others.
function translate(text) {
//Here it goes
var txt = "text=" + text + " ___" + (queue.length - 1);
////////////////
var lang = "&to=fr";
//...no more changes here
}
Finally extract your object in the callback method and remove the appended index and the splitter from the translated text.
function translated(text) {
if (queue.length > 0) {
var splts = text.split(' ___')
var indx = splts[splts.length - 1];
var out = queue[indx];
//remove the out object from the queue
queue.slice(indx, indx + 1);
//remove the index number from the end of the word
text = text.substr(0, text.lastIndexOf(indx) - 4);
out.text(text);
}
}

Categories

Resources