I want to restrict user to vote only one time for a question using
$localstorage.
Here is my code:
HTML:
<ul>
<li ng-repat="question in questions"> {{question.text}}
<button ng-click="upvote(question)">Vote</button>
</li>
JS:
$scope.upvote = function(question){
var votedQuestions = [];
$localStorage.votedQuestions = votedQuestions;
if($localStorage.votedQuestions.indexof(question._id) === -1){
$localStorage.votedQuestions.push(question._id);
console.log("Thanks for Voting");
}
else {
console.log("You already voted to this question");
}
}
}
it is giving me error like $localStorage.votedQuestions.indexof is not a function
and it's not storing multiple questions, it's just updating the question id in localstorage array on other question click
You always set your $localStorage.votedQuestions to an empty array thus user will always have the possibility to vote to all questions.
Just remove this line and it will works fine
//APP
angular.module('myApp')
.run(['$localStorage', function($localStorage) {
$localStorage.votedQuestions = [];
}])
//Controller
$scope.upvote = function(question) {
if ($localStorage.votedQuestions.indexof(question._id) === -1) {
$localStorage.votedQuestions.push(question._id);
console.log("Thanks for Voting");
} else {
console.log("You already voted to this question");
}
}
Related
I am working on an HTML quiz recently, which is a page shown before a company page we use in my department. If the user answers correctly, then he can get the link to the page he needs to work.
However, when he answers wrongly, he gets a message and he can answer again, but the "Wrong Answer" that he got previously is still shown. That is what i don't want to happen.
The code of the quiz.js file is shown below. Also i post the HTML code of the answer section.
$(document).ready(function()
{
$("#results").click(function() {
if (!$("input[#name=q1]:checked").val())
{
alert("You're not done yet!");
}
else
{
var cat1name = "1";
var cat11name = "None";
var cat1 = ($("input[#name=q1]:checked").val() != "b"); // correct answer
var cat11 = (!cat1); var categories = [];
if (cat1) { categories.push(cat1name) };
if (cat11) { categories.push(cat11name) };
var catStr = 'You answered the following questions incorrectly: ' + categories.join(', ') + '';
$("#categorylist").text(catStr);
$("#categorylist").show("slow");
if (cat1) { $("#category1").show("slow"); };
if (cat11) { $("#category11").show("slow"); };
{ $("#closing").show("slow"); };
}
});
});
<div id="results">
Answer
</div>
<div id="category1">
<p>
<strong>Wrong answer!</strong>
</p>
</div>
<div id="category11">
<p>You answered correctly!</p>
<p><a href="somelink</a></p>
</div>
</div>
</body>
</html>
I am a newbie in angularjs.
I was stuck on a code and wanted some help.
I am having a controller called watchlist controller in which I am getting the data which is to be displayed in the watchlist.
However I want to display the data only once the watchlist tab is clicked.
This is the Html code :-
<div class='watchlist' >
<button class='btn' id="watchList" ng-click="fetchUserWatchlist()" watchlist-popover ng-controller="WatchlistController">
<i class="hidden-tablet hidden-phone"></i>
<span class = 'mywatchlist'>My Watchlist</span>
<div class = 'watchlist-spinner ' ></div>
</button>
</div>
My controller(watchlist):-
$scope.fetchUserWatchlist = function(pageno,callback){
$scope.isLoading = true;
$rootScope.isrequest = true;
userAPI.myWatchlist({userid:$rootScope.getUser().userid,pageno:pageno}, function(r) {
if (_.isNull(r.watchlistdata)) {
if(typeof callback == 'function'){
callback();
}
if(pageno == 1){
$scope.watchlist = [];
$scope.watchlistCount = 0;
}
if (!$rootScope.apiCalled && pageno == 1){
if(!_.isUndefined($rootScope.watchlistClicked) && $rootScope.watchlistClicked){
$rootScope.$broadcast("watchlist::click");
imageLoadingIndicator();
}
$rootScope.apiCalled = true;
}
return false;
}
if (!_.isUndefined(r.watchlistdata.watchlist)){
var rawData = [];
var tempWatchlist = $scope.watchlist;
if (_.isArray(r.watchlistdata.watchlist))
rawData = r.watchlistdata.watchlist;
else
rawData = [r.watchlistdata.watchlist];
if (pageno == 1) {
$scope.watchlistCount = parseInt(rawData[0].totalcount);
}
if ($scope.watchlist.length == 0 || ($scope.watchlist.length > 0 && pageno == 1))
$scope.watchlist = rawData;
else
_.each(sortByDate(rawData),function(item){
if (! _.some(tempWatchlist,function(existingItem){ return existingItem.programmeid == item.programmeid; }))
{
$scope.watchlist.push(item);
}
});
$scope.watchlistPage += 1;
$timeout(function(){
if (!$rootScope.apiCalled && pageno == 1){
if(!_.isUndefined($rootScope.watchlistClicked) && $rootScope.watchlistClicked){
$rootScope.$broadcast("watchlist::click");
imageLoadingIndicator();
}
$rootScope.apiCalled = true;
}
},1);
$rootScope.isrequest = false;
if(typeof callback == 'function'){
callback();
}
}else
$rootScope.end = true;
});
};
So basically I want to implement ng-click on the controller but here in the above scenario it does not help..The data is called before the button is clicked.
Please help me with this
ng-click will work using the scope:
ng-click="executeThis()"
will look in the $scope for a variable named 'executeThis'. F.e.:
$scope.executeThis = function(){
// Do stuff you want
};
So when you click the element that has this ng-click attribute, the executeThis function on the scope will be executed. In this function you should do whatever you want to do. To display something when you click it, you could use the function to set a variable on the scope to true and then use ng-show to display what you want to display.
HTML:
<div ng-show="varX">someDiv</div>
JS inside controller:
$scope.varX = false;
So whenever you set this variable to true, your element should be shown.
However, I do suggest following some tutorials since I suspect you don't yet grasp how angular works.. Understanding how the fundamentals of angular work is definitely necessary if you want to develop an app.
try
<button class='btn' id="watchList" ng-click="myClickFunction()" watchlist-popover ng-controller="WatchlistController">
The best way to learn (IMHO) is documentation :-)
I am writing an app where I want to edit collection inside of another collection. Because of this, I have a repeating form for each element of the collection.
Full example is http://plnkr.co/edit/SP5IRaZZJfTaE9DISrXs?p=preview below is the key part:
<div ng-repeat="u in users" class="user">
<div>{{u.name}} <button ng-click="delete(users, $index)">X</button></div>
<div class="contacts">Contacts:
<ul><li ng-repeat="c in u.contacts">{{c.name}}
<button ng-click="delete(u.pseudos, $index)">X</button></li>
<!-- This will be users[index].newContactName - ugly... -->
<li><input type="text" ng-model="u.newContactName" />
<button ng-click="addContact($index)">add contact</button></li></ul>
</div>
</div>
<!-- This will be $scope.newUser - no problem -->
<input type="text" ng-model="newUser" /><button ng-click="addUser()">add user</button>
This kind of worked, until I needed to watch the collection - now editing newContactName triggers my "deep" watch:
$scope.$watch('users', function(newUsers, oldUsers) {
// $scope.log = $scope.log + "users updated\n";
}, true);
What is the "canonical" way of doing such things in Angular? Should I have a parallel collection of "new contacts" per each user, so watching users will be unaffected? (keeping it in sync will be weird)
I would watch it this way:
$scope.$watch('users', function(newUsers, oldUsers) {
//detect changes in user list
if (newUsers.length > oldUsers.length) {
alert("user added\n")
//do something
return;
}
if (newUsers.length < oldUsers.length) {
alert("user deleted\n")
//do something
return;
}
//nothing has changed in users. Examine contacts (This is the part I am not proud of, since it may take bloody ages with thousands of users and contacts)
angular.forEach(newUsers, function(user, index) {
if (user.contacts.length > oldUsers[index].contacts.length) {
alert('Contact added to: ' + user.name);
//do something
return;
}
if (user.contacts.length < oldUsers[index].contacts.length) {
alert('Contact deleted from: ' + user.name);
//do something
return;
}
})
//nothing has changed in contacts too? Must be some lousy edit!
}, true);
Not sure if this is canonical angular zen or if the new watchCollection is better suited. But, hey, it works: Forked Plunker with lots of Alerts
For now I ended up going with having a parallel array of forms, and updating it in parallel, I am having other collections under each user and this "new forms" collection can hold fields for all of them: http://plnkr.co/edit/nyrI1zXTP3JyZlqs1fWJ?p=preview (added logging of watch-updates too)
Key parts:
<div ng-repeat="u in users" class="user">
<div>{{u.name}} <button ng-click="delete($index, [users, userNewForms])">X</button></div>
<div class="contacts">Contacts:
<ul><li ng-repeat="c in u.contacts">{{c.name}}
<button ng-click="delete($index, u.contacts)">X</button></li>
<li><input type="text" ng-model="userNewForms[$index].newContactName" />
<button ng-click="addContact($index)">add contact</button></li></ul>
</div>
</div>
<input type="text" ng-model="newUser" /><button ng-click="addUser()">add user</button>
Javascript:
$scope.addContact = function(userIndex) {
var user = $scope.userNewForms[ userIndex ];
$scope.users[ userIndex ].contacts.push( {'name': user.newContactName } );
}
$scope.delete = function(index, arraysOrArray) {
if(arraysOrArray[0] instanceof Array) {
for( var i = 0; i < arraysOrArray.length; ++i ) {
arraysOrArray[i].splice( index, 1 );
}
}
else {
arraysOrArray.splice( index, 1 );
}
}
...
function computeNewContactForms(users) {
var result = [];
for( var u in users ) {
result.push( makeNewContactForm() );
}
return result;
}
function makeNewContactForm() { return { 'newContactName': '' }; }
Most interesting thing was a discovery that if I use for(a in arrayOrArrays) instead of an index-based iteration, then I get an exception. It looks like "in" form triggers immediate update of bindings or something.
I've a list on ng-repeat that displays a list of results from a $http query (bind to an input). I'd like both for the list to disappear when the user clicks on one of the results and for the initial empty value of the model to be restored.
Basically, the functionality is as follows:
User searches term, list displays results, user clicks on result, list disappears, user clicks on input again to make another search, list with new results appear.
So far I've managed to make the list disappear, but not to make it appear again when the user makes another search.
Here's the relevant code:
<input type="text" ng-model="name" ng-click="Research()"/>
<ul ng-hide="clicked" ng-show="retype">
<li ng-repeat="result in results" ng-click="getDetails(result.id)">{{result.title}}</li>
</ul>
And the JS:
function Ctrl($scope, $http) {
var get_results = function(name) {
if (name) {
$http.get('http://api.discogs.com/database/search?type=artist&q='+ name +'&page=1&per_page=8').
success(function(data3) {
$scope.results = data3.results;
});
}
}
$scope.name = '';
$scope.$watch('name', get_results, true);
$scope.getDetails = function (id) {
$http.get('http://api.discogs.com/artists/' + id).
success(function(data) {
$scope.artist = data;
});
$http.get('http://api.discogs.com/artists/' + id + '/releases?page=1&per_page=500').
success(function(data2) {
$scope.releases = data2.releases;
});
$scope.clicked = true;
}
function Research(){
$scope.retype = true,
$scope.name = '';
}
Plunkr is down, I'll make one as soon as possible. Any idea about what am I missing?
I tidied up your code a little bit. Please note that the div is shown only when artist is defined. So when it is set to undefined by the $scope.clear() method, the mentioned div is hidden.
Html part:
<div ng-controller="Ctrl">
<input type="text" ng-model="name" ng-focus="clear()"/>
<ul>
<li ng-repeat="result in results" ng-click="getDetails(result.id)">{{result.title}}</li>
</ul>
<div ng-show="artist">
<h1>Artist</h1>
<ul>
<li>{{artist.name}}</li>
<li>{{artist.release_url}}</li>
<li>{{artist.uri}}</li>
<li>{{artist.resource_url}}</li>
</ul>
</div>
</div>
JavaScript part:
var myApp = angular.module('myApp',[]);
function Ctrl($scope, $http) {
$scope.name = undefined;
$scope.artist = undefined;
$scope.results = undefined;
var search = function (name) {
if (name) {
$http.get('http://api.discogs.com/database/search?type=artist&q='+ name +'&page=1&per_page=8').
success(function(data3) {
$scope.results = data3.results;
});
}
}
$scope.$watch('name', search, true);
$scope.getDetails = function (id) {
$http.get('http://api.discogs.com/artists/' + id).
success(function(data) {
$scope.artist = data;
});
$http.get('http://api.discogs.com/artists/' + id + '/releases?page=1&per_page=500').
success(function(data2) {
$scope.releases = data2.releases;
});
}
$scope.clear = function () {
$scope.name = undefined;
$scope.artist = undefined;
$scope.results = undefined;
}
}
There is working JSFiddle.
Your Research function is unnecessary because you don't need ng-show and ng-hide same time...
secondly you set clicked to ok but never set it false again after your research done...
here is working PLUNKER
Try using just one ng-hide or ng-show, instead of both. Since you never set clicked back to false, it is probably overriding the retype.
Both functions are two-way, so you can just use ng-hide="clicked", and inside function Research, set $scope.clicked to false.
In the following code, whenever you delete an item from the delete link in the list, it will only delete the item from the list, but it will not delete the currently selected item. (The item displaying once you click on it). However, if you click on the delete link next to the currently selected item, it will delete from both places.
To replicate what I'm seeing:
Add a bunch of items by typing in the text box and hitting enter a few times.
Select one of the items from the list.
Click delete next to the item when it displays below.
This is the correct behavior.
Select another item you created earlier.
Now click the delete link next to the item in the list.
The item is removed from the list, but not the currently displayed item.
When I step into the code $scope.currentUser is undefined when I click on the delete link in the list.
Why is this happening?
<html ng-app="myApp">
<head>
<script src="http://code.angularjs.org/1.0.1/angular-1.0.1.min.js"></script>
<script>
var app = angular.module('myApp', []);
app.config(function($routeProvider) {
$routeProvider.when('/User/:id', {
controller: UserCtrl,
template: '<h1>{{currentUser.name}}</h1> <a ng-click="deleteUser(currentUser.id)">delete me</a>'
});
});
app.factory('userSvc', function(){
return new UserService();
});
function UserCtrl($scope, $routeParams, $location, userSvc) {
var currUser = userSvc.getUser($routeParams.id);
$scope.currentUser = currUser;
$scope.users = userSvc.getAllUsers();
$scope.addUser = function () {
var user = {
id: userSvc.nextId(),
name: $scope.addUserName
};
userSvc.addUser(user);
$scope.addUserName = '';
$location.url('/User/' + user.id);
};
$scope.deleteUser = function(id) {
if($scope.currentUser != null && $scope.currentUser.id == id) {
$scope.currentUser = null;
}
userSvc.delete(id);
};
};
function UserService() {
var users = [{id: 1, name: 'Ben' }];
this.delete = function(id) {
for(var i = 0; i < users.length; i++) {
var user = users[i];
if(user.id == id) {
users.splice(i,1);
}
}
};
this.addUser = function(user) {
users.push(user);
};
this.getAllUsers = function() {
return users;
};
this.getUser = function(id) {
for(var i = 0; i < users.length; i++) {
var user = users[i];
if(user.id == id) {
return user;
}
}
};
this.nextId = function() {
var maxId = 0;
for(var i = 0; i < users.length; i++) {
var user = users[i];
maxId = Math.max(maxId, user.id);
};
return maxId + 1;
};
}
</script>
</head>
<body>
<div ng-controller="UserCtrl">
<form ng-submit="addUser()">
<input ng-model="addUserName" type="text"/>
<input type="submit" value="Add"/>
</form>
<ul>
<li ng-repeat="user in users">{{user.name}} <a ng-click="deleteUser(user.id)">delete</a></li>
</ul>
</div>
<div ng-view></div>
</body>
</html>
It turns out that selecting a user from the list actually also created a brand new scope that was seperate from the one used to bind the list.
Thanks to Gloopy's comment above to check out Batarang, I was able to see this happen. If this happens to help you, please +1 his comment.
According to the documentation on Scopes some directives will actually cause a new scope to be created. I'm assuming that clicking a link that is being handled by the $routeProvider also results in the creation of a whole new scope tree, likely because it's creating another instance of that controllor.