I have a little problem.
I have a "use-button" which sets a cookie, telling that this deal is used. The button switch state to disabled.
The problem is that, if you go back and forwards, the button is no longer disabled and you can still use the button. If you refresh the page the button will be disabled.
This is my code:
export default Ember.Controller.extend(MobileHelper, {
goodie: Ember.computed.alias('model'),
tracker: Ember.inject.service(),
used: undefined,
fieldUsed: function(){
var pack_id = this.get('goodie.packContents.firstObject.id');
var cookies;
if (this.cookie.getCookie('gp_pv') === undefined) {
return false;
} else {
cookies = JSON.parse(this.cookie.getCookie('gp_pv'));
}
return cookies[String(pack_id)] === 1;
}.property('goodie.packContents.firstObject.id'),
profileComponent: function() {
return `goodie-${this.get('goodie.type')}-profile`;
}.property('goodie.type'),
actions: {
markSwiped: function() {
var cookies;
if (confirm("Er du sikker?")){
if (this.cookie.getCookie('gp_pv') === undefined){
cookies = {};
} else {
cookies = JSON.parse(this.cookie.getCookie('gp_pv'));
}
var pack_id = this.get('goodie.packContents.firstObject.id');
if (cookies[String(pack_id)] !== 1){
cookies[String(pack_id)] = 1;
}
jQuery("#itemUsable").hide();
jQuery("#itemUsed").show();
this.get('tracker').trackGoodieExternalLinkClick(this.get('goodie'));
this.cookie.setCookie('gp_pv', JSON.stringify(cookies), { expires: 50000, path: '/' });
this.container.lookup('view:toplevel').rerender();
route.transitionTo("index")
}
}
}
});
{{#if fieldUsed}}
<style>
#itemUsable {display:none;}
#itemUsed {display:block;}
</style>
{{else}}
<style>
#itemUsable {display:block;}
#itemUsed {display:none;}
</style>
{{/if}}
<div class="container" id="itemUsed">
<div class="goodie-page-swipe-action">
<div class="row">
<div class="col-xs-offset-3 col-xs-6">
<div class="btn gp-btn-primary btn-block btn-lg disabled">{{ t 'goodie.used'}}</div>
</div>
</div>
</div>
</div>
<div class="container" id="itemUsable">
<div class="goodie-page-swipe-action">
<div class="row">
<div class="col-xs-offset-3 col-xs-6">
<div {{ action 'markSwiped' }} class="btn gp-btn-primary btn-block btn-lg">{{ t 'goodie.use'}}</div>
</div>
</div>
</div>
</div>
Computed property values are normally cached and only updated when the values of the dependent keys change. From the provided code it is not immediately obvious that, when markSwiped gets run, goodie.packContents.firstObject.id immediately changes. I guess it doesn't, since fieldUsed and thus your templates do not get updated (which means the cookie value that you do update is never re-evaluated, until a full page refresh).
Things that come to mind that you could try:
You could try to make fieldUsed a volatile property which would hopefully cause it to be re-evaluated on every use (no longer cached)
fieldUsed: function() {...}.volatile()
Make fieldUsed depend on some other value instead, or in addition. For instance, as a crutch you could test some extraneous counter type variable that simply gets incremented somewhere in markSwiped
crutchCounter: 0,
fieldUsed: function() {}.property('goodie.packContents.firstObject.id', 'crutchCounter'),
markSwiped: function() {...; this.incrementProperty('crutchCounter'); ...}
If either of these work, you can then also forego the jQuery DOM manipulation you have going on in markSwiped.
Related
I want to ask about javascript, how to show a div once in one visit?
I have the code that I have work below. But still not working.
JS Show Div Once Per Time
(function() {
var visited = sessionStorage.getItem('visited');
if (!visited) {
document.getElementById("popupMode").style.visibility = "visible";
sessionStorage.setItem('visited', true);
}
})();
What I want:
I have a popup div to give the user the option to choose the mode. When user have selected the popup will disappear. When I refresh the page I want the popup not appear again, it appears only once at the beginning of our visit to the web.
If you don't mind, I also have a switcher mode in the popup but it won't switch.
for the full code, you can see in My Codepen
POPUP MODE
<!-- Popup Mode -->
<div id="popupMode">
<div class="container-fluid p-0 h-100">
<div class="row h-100">
<div class="col-12 main-content">
<div id="modeChoice">
<div class="title">
<h2>Welcome</h2>
<p>
You can switch the button from light mode<br>to dark mode
</p>
</div>
<div class="choose-mode">
<div id="modeSwitcher">
<input type="checkbox" class="checkbox" id="chk" />
<label class="label" for="chk">
<i class="fas fa-moon"></i>
<div class="ball"></div>
</label>
</div>
</div>
<div id="buttonPopupMode">
UNDERSTAND
</div>
</div>
</div>
</div>
</div>
</div>
FULL JS
window.onload = function() {
(function() {
var visited = localStorage.getItem('visited');
if (!visited) {
document.getElementById("popupMode").style.visibility = "visible";
localStorage.setItem('visited', true);
}
})();
if (localStorage.darkMode == "true") {
document.body.classList.toggle('dark');
document.getElementById("chk").checked = true;
} else {
document.body.classList.toggle('light');
}
};
document.getElementById("chk").addEventListener('change', () => {
document.body.classList.toggle('dark');
document.body.classList.toggle('light');
localStorage.darkMode = (localStorage.darkMode == "true") ? "false" : "true";
});
$("#popupMode").delay(3000).fadeIn(500);
$("#buttonPopupMode .button-primary").on('click', function() {
$('#popupMode').hide();
})
Move this line $("#popupMode").delay(3000).fadeIn(500); inside if (!visited) {...}.
Updated code will be like below.
window.onload = function() {
(function() {
var visited = localStorage.getItem('visited');
if (!visited) {
document.getElementById("popupMode").style.visibility = "visible";
localStorage.setItem('visited', true);
// Add below line.
$("#popupMode").delay(3000).fadeIn(500);
}
})();
if (localStorage.darkMode == "true") {
document.body.classList.toggle('dark');
document.getElementById("chk").checked = true;
} else {
document.body.classList.toggle('light');
}
};
document.getElementById("chk").addEventListener('change', () => {
document.body.classList.toggle('dark');
document.body.classList.toggle('light');
localStorage.darkMode = (localStorage.darkMode == "true") ? "false" : "true";
});
// remove below line.
// $("#popupMode").delay(3000).fadeIn(500);
$("#buttonPopupMode .button-primary").on('click', function() {
$('#popupMode').hide();
})
P.S.
localStorage vs sessionStorage
localStorage and sessionStorage accomplish the exact same thing and have the same API, but with sessionStorage - the data is persisted only until the window or tab is closed, while with localStorage - the data is persisted until the user manually clears the browser cache or until your web app clears the data. I would suggest to use localStorage but its up to you and your requirement you can choose preferable.
I have the following html structure in my web application.
This is a group of <div>s which contain information about items. Specifically there are two <span> tags with pending and done quantities (integer values).
Clicking on other page elements will modify pending and done values.
Is it possible to track those changes and apply a class to the whole <div> when those values are the same?
So the whole <div id="{{ item.id }}"> will have a green background when pending and done match and no color background when values do not match. The actual action to be done is not relevant, what I miss is understanding the right approach in jQuery to monitor values in two html fields.
<div id="{{ item.id }}" href="#" state="{{ item.state }}" class="item">
<div class="row">
<div class="col-xs-4">
<span name="pending">{{ item.pending }}</span>
</div>
<div class="col-xs-4">
<span name="done">{{ item.done }}</span>
</div>
</div>
</div>
Use find and text functions along with these selectors '[name="pending"]' '[name="done"]'.
To listen to javascript modifications (jQuery), an alternative is to override the .val function.
var originalValFn = jQuery.fn.val;
jQuery.fn.val = function(value) {
originalValFn.apply(this, arguments);
if (value !== undefined) {
$('#done').trigger('input');
$('#pending').trigger('input');
}
};
Look at this code snippet.
The function updateSection must be called when the user changes the values.
var target = $('#myId');
var originalValFn = jQuery.fn.val;
jQuery.fn.val = function(value) {
originalValFn.apply(this, arguments);
if (value !== undefined) {
$('#done').trigger('input');
$('#pending').trigger('input');
}
};
var updateSection = function() {
var pending = target.find('[name="pending"]').text();
var done = target.find('[name="done"]').text();
if (pending === done) {
target.addClass('green-class');
target.removeClass('red-class');
} else {
target.addClass('red-class');
target.removeClass('green-class');
}
}
$('#pending').on('input', function(e) {
target.find('[name="pending"]').text(e.target.value);
updateSection();
});
$('#done').on('input', function(e) {
target.find('[name="done"]').text(e.target.value);
updateSection();
});
$('#done').val('3');
$('#pending').val('4');
//updateSection();
.green-class {
background-color: green;
}
.red-class {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="myId" href="#" state="{{ item.state }}" class="item">
<div class="row">
<div class="col-xs-4">
<span name="pending">222</span>
</div>
<div class="col-xs-4">
<span name="done">222</span>
</div>
</div>
</div>
<hr>
<p>Enter values to test:</p>
<input id='pending' placeholder='pending'>
<input id='done' placeholder='done'>
Resources
.find()
.text()
.on()
Sure. Place an input element inside each span and have the values actually be stored in the input. Then, set up input event handlers for those input elements that simply compare the values of the inputs. If they are the same. Apply a class.
// Get inputs
var $pending = $(".pending");
var $done = $(".done");
// Set up event handler
$pending.on("input", test);
$done.on("input", test);
function test(){
if($pending.val() === $done.val()){
$("div#parent").addClass("match");
} else {
$("div#parent").removeClass("match");
}
}
input { outline:none; border:none; }
.pending { background-color:rgba(255, 100, 100, .5); }
.done { background-color:rgba(255, 255, 100, .5); }
.match { background-color:rgba(100, 255, 100, .5); }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>For testing, type different (and then the same) values into the two fields</h1>
<div id="parent" href="#" state="{{ item.state }}" class="item">
<div class="row">
<div class="col-xs-4">
<span name="pending"><input class="pending"></span>
</div>
<div class="col-xs-4">
<span name="done"><input class="done"></span>
</div>
</div>
</div>
First: the "name" attribute only applies to input elements, you probably want to use the "id" attribute.
I would also suggest creating a function to check for equality, something like this:
var pendingDone = function(){
if($("#pending").text() === $("#done").text()) {
$("#pending").addClass("green");
$("#done").addClass("green");
} else {
$("#pending").removeClass("green");
$("#done").removeClass("green");
}
}
I would suggest just calling this function in all instances that modify the values, since the change and input listener suggested in another answer will not fire if the value is modified by javascript instead of user interaction.
I'm trying to use an onclick event with an anchor tag that will change the innerHTML of another element on the page. I'm not sure what I'm doing wrong, so all the code I'm using is below. I hope you guys can point out my mistake and tell me what it was I misunderstood. The JavaScript file is included after the body, but you can see that on the JSfiddle here. So, when I click Settings, I want the BookmarkList div to show it's own HTML code, and the same for Home. The BookmarkList div will be the center of attention for this site. I'm just not sure what I'm doing wrong for this.
HTML:
<body id="bodyBG">
<div class="wrapper">
<div class="box header">
Header
</div>
<div class="box content">
<div class="box subcontent1">
<div class="sdfgsdfgsdfg"><input id="categoryName" placeholder="Category Name"></input></div>
<div class="sdfgsdfg"><input id="urlLink" placeholder="Site Address"></input></div>
<div class="sdfgsddfg"><input id="bookmarkName" placeholder="Bookmark Name"></input></div>
<div><button>Save</button></div>
<hr>
<input placeholder="Search Bookmarks"></input>
<button>Search</button>
</div>
<div class="box subcontent2">
Settings
<hr>
Home
Back
Forwards
</div>
<div id="bookmarkList" class="box subcontent3 bookmark-list">
</div>
</div>
<div class="box footer">Footer</div>
</div>
<script src="assets/js/bookmark-action-script.js"></script>
</body>
JavaScript:
var settingsNav = document.getElementById('settingsNav');
var homeNav = document.getElementById('homeNav');
var changeThis = document.getElementById("bookmarkList");
function myFunction(this) {
if (this === settingsNav) {
changeThis.innerHTML = "<h3>Bookmarks</h3><hr>";
}
else if (this === homeNav) {
changeThis.innerHTML = "<h3>Bookmarks</h3><hr><p>Store all your bookmarks here!</p><ul><li>An secure storage means for your privacy needs!</li><li>24/7 Availability</li></ul>";
}
else (this != settingsNav | homeNav) {
changeThis.innerHTML = "Nothing to see here!";
}
};
document.getElementById("settingsNav").addEventListener("click");
document.getElementById("homeNav").addEventListener("click");
The Solution:
I always add the solution that was appropriate for my problems, so future observers can see what issue I had and what the solution was. My issue was not adding the function to my eventlistener. You do not need to specify onclick events inside the HTML code if you specify event listeners with accompanying functions in your JavaScript code. But without the functions tied to the eventlisteners, nothing will happen. I understand that now.
var settingsNav = document.getElementById('settingsNav');
var homeNav = document.getElementById('homeNav');
var changeThis = document.getElementById("bookmarkList");
function myFunction(event) {
var el = this;
if (el === settingsNav) {
changeThis.innerHTML = "<h3>Bookmarks</h3><hr>";
} else if (el === homeNav) {
changeThis.innerHTML = "<h3>Bookmarks</h3><hr><p>Store all your bookmarks here!</p><ul><li>A secure storage means for your privacy needs!</li><li>24/7 Availability</li></ul>";
} else if (el != settingsNav || homeNav) {
changeThis.innerHTML = "Nothing to see here!";
}
};
document.getElementById("settingsNav").addEventListener("click", myFunction);
document.getElementById("homeNav").addEventListener("click", myFunction);
Remove attribute event handlers from HTML. Change function (this) to function (event). You did not add an event handler at.addEventListener()call, where you can passmyFunction` as a reference to to function to call when event is dispatched.
OR in JavaScript should be || instead of | at second else..if
Note, <input> element is self-closing, </input> is invalid HTML.
<body id="bodyBG">
<div class="wrapper">
<div class="box header">
Header
</div>
<div class="box content">
<div class="box subcontent1">
<div class="sdfgsdfgsdfg"><input id="categoryName" placeholder="Category Name"></div>
<div class="sdfgsdfg"><input id="urlLink" placeholder="Site Address"></div>
<div class="sdfgsddfg"><input id="bookmarkName" placeholder="Bookmark Name"></div>
<div><button>Save</button></div>
<hr>
<input placeholder="Search Bookmarks">
<button>Search</button>
</div>
<div class="box subcontent2">
Settings
<hr>
Home
Back
Forwards
</div>
<div id="bookmarkList" class="box subcontent3 bookmark-list">
</div>
</div>
<div class="box footer">Footer</div>
</div>
<script>
var settingsNav = document.getElementById('settingsNav');
var homeNav = document.getElementById('homeNav');
var changeThis = document.getElementById("bookmarkList");
function myFunction(event) {
var el = this;
if (el === settingsNav) {
changeThis.innerHTML = "<h3>Bookmarks</h3><hr>";
} else if (el === homeNav) {
changeThis.innerHTML = "<h3>Bookmarks</h3><hr><p>Store all your bookmarks here!</p><ul><li>An secure storage means for your privacy needs!</li><li>24/7 Availability</li></ul>";
} else if (el != settingsNav || homeNav) {
changeThis.innerHTML = "Nothing to see here!";
}
};
document.getElementById("settingsNav").addEventListener("click", myFunction);
document.getElementById("homeNav").addEventListener("click", myFunction);
</script>
</body>
Your code works fine in Chrome by fixing couple of syntax errors.
update else to else if
else if (clk != settingsNav | homeNav)
update this parameter to something else in myFunction
function myFunction(clk)
no need to add event since you called myFunction in onclick, so remove:
document.getElementById("settingsNav").addEventListener("click");
document.getElementById("homeNav").addEventListener("click");
Somehow it didn't work in jsfiddler.
I asked this question but the specific question I'm asking has changed dramatically.
I have a piece of code:
<div ng-attr-controller="{{pings || 'PingsCtrl as pings' }}">
<h1 ng-click="pings.press()">asdf</h1>
</div>
This code is injected into two html pages. One page already calls PingsCtrl. The other doesn't. I'm really trying to keep this code DRY and I only want to have one reference of the code above.
How can I write the code above to generate ng-controller if PingsCtrl hasn't already instantiated.
Here are the two html pages.
HTML
// First page
<html ng-app="coolApp">
<div ng-controller="PingsCtrl as pings">
<div ng-attr-controller="{{pings || 'PingsCtrl as pings' }}">
<h1 ng-click="pings.press()">asdf</h1>
</div>
</div>
</html>
// Second page
<html ng-app="coolApp">
<div ng-attr-controller="{{pings || 'PingsCtrl as pings' }}">
<h1 ng-click="pings.press()">asdf</h1>
</div>
</html>
Javascript is here:
angular.module('coolApp', [])
.controller('PingsCtrl', function() {
var vm = this;
vm.press = function() {alert(123)};
})
What's wrong and how do I fix this?
Just use a service. It's really the intended structure for having common data and functionality between pages.
Part of the problem with what you were attempting is, whether or not you manage to preserve the controller, Angular has its own management that won't follow you with that, and will be refreshing components without you. You'll run into things like a $scope that doesn't actually match the page you're looking at, and it ends up causing more problems than it's worth.
I do have a solution but I also echo other people's concerns about the approach. You may want to have a global controller that you drop on the body for things that can happen anywhere and in most of the other controllers and just call through that. Eg
<body ng-controller="GlobalCtrl as gc">
<h1 ng-click="gc.pingPress()"></h1>
</body>
Anyway here is what I came up with.
<div ng-if="pings">
<h1 ng-click="pings.press()">asdf</h1>
</div>
<div ng-if="!pings">
<div ng-controller="PingsCtrl as pings">
<h1 ng-click="pings.press()">asdf</h1>
</div>
</div>
This will work if it is dropped inside or outside of an existing PingsCtrl.
Here is a plunker.
https://plnkr.co/edit/4x0kSazcg0g0BsqPKN9C?p=preview
Please, check my solution to see how to share data between controllers
var app = angular.module('myApp', []);
app.controller("aCtrl", function ($scope, PingList) {
$scope.addPing = function() {
PingList.add('Ping A');
};
});
app.controller("bCtrl", function ($scope, PingList) {
$scope.addPing = function() {
PingList.add('Ping B');
};
});
app.factory('PingList', function () {
var pings = ['Ping1', 'Ping2'];
return {
add: function(ping) {
pings.push(ping);
},
get: function () {
return pings;
}
};
});
app.directive('pingList', function(PingList) {
return {
restrict: 'EA',
link: function($scope) {
$scope.pings = PingList.get();
$scope.press = function(ping) {
alert(ping);
}
},
template: '<ul><li ng-repeat="ping in pings" ng-click="press(ping)">{{ping}}</li></ul>'
};
});
a, li {
cursor: pointer;
}
a {
color: blue;
text-decoration: underline;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="aCtrl" style="float: left">
<a ng-click="addPing()">click to add A ping</a>
<ping-list></ping-list>
</div>
<div ng-controller="bCtrl" style="float: right">
<a ng-click="addPing()">click to add B ping</a>
<ping-list></ping-list>
</div>
<div style="clear: both"></div>
</div>
<script>
$(document).foundation(
var count = 1
$("button.test").click(function(){
if ($("p.change-me").text() === "OFF") {
$("p.change-me").text("ON")
count = count + 1
}
else if ($("p.change-me").text() === "ON") {
$("p.change-me").text("OFF")
count = count + 1
}
$("p.counter").text(count)
})
)
</script>
Very simply, I want to show the count as I am pressing this On and Off button. However, when I add the "var count = 1", my button no longer works. When I get rid of that line, the button will turn the text in the tag from ON to OFF and from OFF to ON.
How come? As you can probably tell, I am teaching myself JQuery.
Thanks!
HTML as requested:
<div class="row">
<div class="small-6 columns text-center">
<button class="button radius test">CLICK THIS</button>
</div>
<div class="small-6 columns text-center">
<p class="change-me">OFF</p>
</div>
</div>
<div class="row">
<div class="small-12 columns text-center">
<p>Here we will print how much fun you are having:</p>
<p class="counter">0</p>
</div>
</div>
Take your code out of the foundation() call. Also try to remember using semicolons.
$(document).foundation();
var count = 1;
$("button.test").click(function(){
if ($("p.change-me").text() === "OFF") {
$("p.change-me").text("ON");
count = count + 1;
}
else if ($("p.change-me").text() === "ON") {
$("p.change-me").text("OFF");
count = count + 1;
}
$("p.counter").text(count);
})
#Romain's answer is correct, but just to add to that... foundation is a method-call, and you were trying to put javascript code in the section where you normally put parameters (ie inside the ()). javascript code normally has to go inside of a function's body, not in the section where you type the parameters.