Unable to append local storage data across the domain - javascript

I have a massive problem, with little time to resolve it. I am creating my first mobile app for property search as a university project (its not based on real properties)
I tried using different keys it does not work, Im not getting the basics.
Basically I have a Jquery mobile app with many external pages which have details for a property, these pages have the same id but on different documents, When a user clicks the button to save, I want the title and the url of the page to be saved in local storage and to be retrieved by a third page called my favorites. The problem I am having is that when I go on each page and click save, it overrides what was already in local storage and it seems like each page has its own storage and as a result my favorites page always has only one favorite (the latest one), rather than a favorite list appending every time I click save. Here is my code:
<div data-role="header" id="samplePlacePage_hd">
<h4 id="hutRef">add#redHut456</h4>
</div>
<div data-role="main" id="samplePlacePage_cont">
<div id="image">
<img src="images/redhut.jpeg" height="200px" width="100%" alt="Hut">
</div>
<div id="place_title">
<p id="hutHeading">Stunning Red Hut in Central Red Beach</p>
</div>
<div>
<h4 style="float: left;">Rent: $2950pw</h4>
<h4 style="float: right;">Deposit: 5500</h4>
</div>
(Same code on both pages)
This was the function I had in my script file:
$(document).on("pagecreate",function (argument) {
var favoritesPlaces = [];
var heading = document.getElementById('hutHeading').innerText;
var ref = document.getElementById('hutRef').innerText;
var refLink = ref.replace("add#","");
document.getElementById('hutFav').onclick = function () {
var newFav = {
title: heading,
link: refLink
};
favoritesPlaces.push(newFav);
console.log(favoritesPlaces);
localStorage.setItem("favorites",JSON.stringify(favoritesPlaces));
}
})
Please help
Thanks

Two additional considerations for you: checking the favorite has not been added already, and allowing the user to have multiple tabs open on pages from your site - adding one page as a favorite should not interfere with adding a different page as a favorite. And not to forget, if the local storage item does not exist create a new one :)
Basically I suggest retrieving local storage, checking for duplicates, updating and saving back to local storage all occur in a single click handler, E.G. by rearranging your code and adding a few lines:
$(document).on("pagecreate",function () {
document.getElementById('hutFav').onclick = function () {
var favoritesPlaces = localStorage.getItem("favorites");
var heading = document.getElementById('hutHeading').innerText;
var ref = document.getElementById('hutRef').innerText;
var refLink = ref.replace("add#","");
var newFav = {
title: heading,
link: refLink
};
favoritesPlaces = favoritesPlaces || '[]'; // string
favoritesPlaces = JSON.parse(favoritesPlaces); // array
if( !favoritesPlaces.some( fave => fave.link === refLink)) {
favoritesPlaces.push( newFav)
console.log(favoritesPlaces);
localStorage.setItem("favorites",JSON.stringify(favoritesPlaces));
}
else {
console.log("already a favorite");
}
}
})
(tested)
Note that clearing localStorage on any page clears it for all pages across a site. Once cleared, its cleared on all pages, there are no more favorites, and any page can be added again without being a duplicate. If a "remove this page from favorites" button is needed, a new function needs to be written to do it.

Related

How can JS Detect changes in the HTML such as ctr+shift+i input?

Here is a website I am currently developing. As a challenge for the user we are asking them to use ctrl+shift+i to interact with the HTML and change certain elements.
How can Javascript, or html/css detect that they changed that?
i.e.
<div>
<p>This is placeholder text</p>
</div>
We want them to change that placeholder text to something specific and then grant them access to a new page.
As posted in the comments, it is possible to load the default content of an element on page load and then periodically scan for changes
window.onload = () => {
let changeCheck = document.querySelector('#this_should_change'); // get the element
let oL = changeCheck.innerHTML; // load the default values
let check = setInterval(() => {
if (changeCheck.innerHTML !== oL) { // if the values are different from the values on load
alert("Stuff changed"); // your code
clearTimeout(check); // clear the interval so that it does not repeat itself
}
}, 100); // this will check the element every second
};
<p id="this_should_change">
Foo
</p>

Modifying chrome extension for new Twitter UI

I have a chrome extension for Twitter where I add a button to all those tweets which have images in them. The code in the content script is something like this:
$(".tweet, .js-tweet").each(function() {
var username = $(this).attr('data-screen-name');
var tweetid = $(this).attr('data-tweet-id');
if (username != null) {
var mediaLinkContainer = $(this).find(".card2")
addButtonToMediaLinkTweets(tweetid, mediaLinkContainer)
// addOverlayToMediaLinks()
var outerContainer = $(this).find(".AdaptiveMediaOuterContainer")
var mediaContainer = $(this).find(".AdaptiveMedia-photoContainer")
if (mediaContainer.length) {
console.log("Photo found in link")
addButtonToPosts(tweetid, outerContainer)
// addOverlayToPosts(outerContainer)
}
}
});
This worked perfectly with the older UI of Twitter, but this doesn't work after the new UI was rolled out. All the class names have changed and the view hierarchy is different as well. I'm trying to navigate through all of that to make my extension work again.
The following class name appears a lot of times - css-1dbjc4n I tried the following to iterate over all the tweets:
$('.css-1dbjc4n.r-1ila09b.r-qklmqi.r-1adg3ll').each(function() {
console.log($(this).html())
})
.css-1dbjc4n r-1ila09b r-qklmqi r-1adg3ll are the classes assigned to the div that is at the second to top most level of a tweet (the topmost div does not have a class or id). However, console.log does not print anything in this case. I need to iterate over the tweets to be able to add my UI element.
Edit:
It seems that jQuery has issues with the new Twitter UI. When I wrote the following in vanilla JavaScript:
var tweetDivs = document.getElementsByClassName("css-1dbjc4n r-1ila09b r-qklmqi r-1adg3ll")
console.log(tweetDivs)
//get images inside the tweets and add button on top of these images
$(tweetDivs).each(function(tweet) {
console.log(tweet)
})
I get a HTML collection in tweetDivs. However, I'm unable to iterate over its elements as its length is 0. The elements show up in console though, but that's probably because the DOM hasn't loaded when this gets called. That's weird because I'm calling the above code from document.ready. I tried replacing document.ready with document.addEventListener("DOMContentLoaded", function(){}) and changed run_at in manifest.json file to document_start but it did not make a difference.

How to update React localstorage?

I have a website that does one of two things. If you have never been to the site, it asks for info, which is stored in localstorage, and then it takes you to the main content. If you have filled out the info before, then it takes you straight to the main content. This is all done in one page.
Currently, my main content page only works upon page reload. This is because React does not have localstorage data to load the main content. It is only rendering the page on load. As stated, this is all to happen on the same page.
<script type="text/babel">
var Weatherapp = React.createClass({
render: function(){
var weatherplace = localStorage.getItem('yourlocation');
var weatherplaceshared = localStorage.getItem('yourlocation').replace(/,/g, ", ");
var weathervane = new XMLHttpRequest();
weathervane.open('GET', 'http://api.openweathermap.org/data/2.5/weather?q='+weatherplace+'&appid=stuff', false);
weathervane.send(null);
var runthru = JSON.parse(weathervane.response);
var weathervalue = runthru.main.temp;
var weatherimage = runthru.weather[0].icon;
var weatherimageplace = "http://openweathermap.org/img/w/"+weatherimage+".png";
return (
<div id="weatherapp_container">
<div id="weatherapp_location">{weatherplaceshared}</div>
<div id="weatherapp_icon"><img src={weatherimageplace}/></div>
<div id="weatherapp_temperature"><p>{weathervalue}°F</p></div>
</div>
)}
});
ReactDOM.render(<Weatherapp />, document.getElementById('weatherapp'));
</script>
I want to restart the render function on a click event. To that end, I have changed my code like so. Note, the submitsuestado is the button that activates my function once input is stored for the first time.
render: function(){
document.getElementById('submitsuestado').addEventListener('click', function(){
var yourcity = document.getElementById('suciudad').value;
var yourstate = document.getElementById('suestate').value;
localStorage.setItem('yourlocation', yourcity+","+yourstate);
From there I duplicate the rest of the code on top. However, this does not work. I am trying to understand where the error lies, and what I might do to make sure that Weatherapp runs both on page load with local storage data stored, as well as on a fresh page where the local storage data is just recently put.
your click event just save value into localstorage, it didn't change the state of your component, so react will not render. if your want to render your component, just try to put your button into your component, and use setState to change the state of your component.

Getting an image to appear on a popup window with Angular JS

This is my first post on StackOverflow and I am teaching myself Angular, so I am a beginner and currently confused.
I am creating a webpage with Angular and one of the pages involve a button and a popup window. I would like to put an image into the popup window, but I am having a lot of trouble with getting this to work.
The step and name properties are successfully appearing in the popup window, but the image is not working. I have tried just getting the url to appear as a string, but that also doesn't work.
I've also tried getting the id property (which is just a string) to appear, but that also doesn't work.
I put only one set of curly brackets around the ctrl.figure in the html because that at least gets me a broken picture icon in the popup window, whereas if I use two curly brackets, as is normally suggested, I get nothing.
I am hosting the website on my local computer and with Chrome Dev tools, keep getting a message that the file is not found. I've checked the file path multiple times and it seems fine. Since I can't get the figure's url to appear as just a string, I'm thinking that the problem might have something to do with the controller.
Any suggestions would be greatly appreciated. The first set of code is the html for the popup window and the second bit is from the controller.
<!--Overlay div for popup window-->
<div ng-show= "ictrl.showValue" class="instAbsolute col-xs-12 col-md-10 ng-cloak">
<span class= "glyphicon glyphicon-remove pull-right" ng-click = "ictrl.hideDetails()"></span>
<h4 class = "text-muted" >{{ictrl.step}}</h4>
<h1 class = "text-grey">{{ictrl.name}}</h1>
<h1 class = "text-grey">{{ictrl.id}}</h1>
<div ng-bind-html="ictrl.description">
</div>
<img class= "img-responsive" ng-src="{ictrl.figure}" alt="{{ictrl.alt}}">
</div>
</div> <!--end of controller -->
</div> <!--end of app -->
angular.module('instructionsApp', ['ngSanitize']).controller('instructionsCtrl',[
function() {
var self = this;
self.showValue = false;
self.showDetails = function(id) {
for (var i = 0; i < this.steps.length; i++) {
if (self.steps[i].id === id) {
self.name = self.steps[i].name;
self.step = self.steps[i].step;
self.description = self.steps[i].description;
self.showValue = true;
}
}
};
self.hideDetails = function() {
self.showValue = false;
};
self.steps = [{
{
name: "Attach Camera",
id: "S1",
step: "Setup",
description: "<p>There are many ways to attach you camera to your laptop. For digital camera output, we recommend connecting the camera with a wire to the faster firewire port – but the USB port will also work. As an example, for analog camera output you can use an external capture device (such as the Dazzle from Pinnacle) with a 3-port composite connector into the camera and a USB connection on the other end of the cable into the laptop. Also, there are many ways to interface a camera to an internal video capture card. See illustrations below:<\/p>"
}, {
name: "Launch VazztCaster",
id: "S2",
step: "Setup",
figure: "../img/instructionsImages/launchVazztCaster.jpg",
description: "<p>Launch the VazztCaster.exe program on your laptop by clicking on the Vazzt icon (red V) on your desktop. After launch, on the home page of VazztCaster click on the Login Icon (person) and enter the Credentials:<\/p><p>Next Click on the Video Settings Icon (blue camcorder) and enter your choice of <\/p><p> <\/p><p>Note that the VazztCaster will automatically set default values, if possible, in the Video Settings fields based on the camera attached, the IP networks it finds, and the audio equipment attached:<\/p><ul><li>Video Capture Devices<\/li><li>Video Resolution<\/li><li>Video Bandwidth<\/li><li>Aspect Ratio<\/li><li>Audio Capture Device<\/li><li>And other Audio parameters. <\/li><\/ul><p>However, you can manually override these. Click the OK button when you are finished.<\/p><p>Most cameras will automatically provide notification of the various resolutions that the camera can support. VazztCaster can detect this and by examining the bandwidth detected, also automatically, VazztCaster sets default resolution and bandwidth.<\/p><p> <\/p><p> <\/p>",
alt: "Launch VazztCaster",
imageCaption: "After launching VazztCaster, this is what your screen should look like."
}];
}
]);
In your instructionController.js -
self.showDetails = function(id) {
for (var i = 0; i < this.steps.length; i++) {
if (self.steps[i].id === id) {
self.name = self.steps[i].name;
self.step = self.steps[i].step;
self.description = self.steps[i].description;
## self.figure = self.steps[i].figure;
## self.alt = self.alt[i].alt;
## self.imageCaption = self.imageCaption[i].imageCaption
self.showValue = true;
}
}
};
The lines starting with ## are the ones you need to add So basically you forgot to loop the above highlighted lines.
Hope this helps.

Adding and removing elements on a web page dynamically using javascript

So I'm using Twitter Bootstrap to create a web page, and I'd like to use their "Alerts" class to dynamically create and dismiss alerts at the bottom of my page. Basically my web page is used to monitor a wireless data acquisition system, so I'd like to be able to dynamically display messages related to that system, i.e. "Warning, Sensor 1 is not responding", and then be able to dismiss it dynamically when the event has passed, or have the user dismiss it.
I'm more of an embedded systems guy, and haven't done much web development, so I'm really not sure where to start. My first inclination would be to do something like this:
<div id="Alert1"></div>
<div id="Alert2"></div>
...
And create enough divs at the bottom of my page to display a reasonable number of messages, then dynamically change them in code with something like:
var Alert1 = document.getElementById("Alert1");
Alert1.className = "alert alert-warning";
$('#Alert1').html("Error: Unable to write to logfile");
I can't imagine that this is a very good way to do it, though, and I'd have to have some way to manage what divs were in use, etc. What is a better way to dynamically create and remove these elements?
Using jQuery you can use append to dynamically add an element to the page.
<div class="alerts"></div>
In JavaScript:
$(".alerts").append("<div id='alert1'>Warning</div>");
Similarly you can remove the element using the remove() function.
You don't need to create a <div> for any and all error messages you have. Just create one <div> and dynamically fill in the appropriate text (or HTML) of the currently active message.
Sample code:
// define this function globally
(function (exports) {
var messages = {};
function addMessage(type, msg) {
if (typeof messages[type] === "undefined") {
messages[type] = [];
}
messages[type].push(msg);
render();
}
function render() {
var html = "";
for (type in messages) {
if (messages.hasOwnProperty(type)) {
for (var i=0, len=messages[type].length; i<len; i++) {
html += type + ": " + messages[type][i];
}
}
}
$("#Alert").html(html);
}
exports.addMessage = addMessage;
})(window);
// somewhere in your code
addMessage("Error", "Unable to write to logfile");
It would be even better to declare "Error" as a constant/variable somewhere:
var ERR_ERROR = "Error";
var ERR_WARNING = "Warning";
You can define a template for your alerts, holding the message and the type of the message.
Then according to the type of the message you would append the message into the page.
Consider the following function
function addAlert(type, message) {
_.templateSettings.variable = "element";
var tpl = _.template($("#alertTemplate").html());
var tplData = {
message: message,
type: type
};
$("#mainContainer").append(tpl(tplData));//the div or container where you want your messages to appear
}
And the template would be
<script type="text/html" id="alertTemplate">
<div class = "alert alert-<%= element.type %>" > <%= element.message %> </div>
</script>
and of course the container of your alerts
<div id="mainContainer">
</div>
Then in your alert handler you would call addAlert with the appropriate parameters.
and to remove all the alerts
$("#mainContainer").find('.alert').remove();
You can find working example at http://jsfiddle.net/hatemalimam/EpM7W/6/

Categories

Resources