I'm trying to create a voting system using AngularJS with the Ionic Framework. I'm using ng-repeat to loop over a series of user posts from a JSON array. Each post has an upvote and a downvote button. After one is selected, I have the button on that post disabled. The problem I'm currently experiencing is keeping that button disabled regardless if the user reopens the app. My goal is to prevent multi-voting. Currently, I'm using this method to disable the button after it's been clicked:
<button class="button button-small button-light" ng-click="upThread({{thread.id}})" ng-disabled="upDisabled[thread.id]">
<i class="icon ion-thumbsup"></i>
</button>
<button class="button button-small button-light" ng-click="downThread({{thread.id}})" ng-disabled="downDisabled[thread.id]">
<i class="icon ion-thumbsdown"></i>
</button>
$scope.upDisabled = {};
$scope.downDisabled = {};
$scope.upThread = function(id) {
...
$scope.upDisabled[id] = true;
$scope.downDisabled[id] = false;
}
$scope.downThread = function(id) {
...
$scope.downDisabled[id] = true;
$scope.upDisabled[id] = false;
}`
And this works great for disabling the buttons. Now, the problem is, I require Cache for the controller to be false, otherwise my new posts do not update in the view when added. This means, when reloading the app or switching between routes/views, the buttons become enabled again, which is not what I want. Additionally, setting cache to true doesn't keep the buttons disabled after the app has been reopened either. I have tried using localstorage to store the $scope.upDisabled and $scope.downDisabled, but it ruins the JSON formatting. I have tried remote storage and received the same result. For example, the $scope.upDisabled and $scope.downDisabled store data like so:
{"2":true, "3":false, "4":true}
and so on. But because storing in localstorage or a database requires me to use JSON.stringify, you can guess that those quotes cause trouble and I end up with nested JSON as well. So, the data from localstorage does not return the correct format. My known problems/options are twofold.
Something else to note: Since this is a mobile/hybrid app using Ionic, I am not using cookies, but I did create a token system to act similarly.
Edit: Thanks to those who replied and your suggestions. I am currently using a MySQL database to keep track of the votes (May switch to SQLite later) @aorfevre: I've taken a look at the SQLite plugin before and will probably use it down the road. I finally got everything working how I want it to.
$scope.upDisabled = {};
$scope.downDisabled = {};
$scope.upCheck = {};
$scope.downCheck = {};
...Votes Loading function up here
...Thread loading Function up here
.finally(function(){
angular.forEach($scope.threads,function(value,index){
angular.forEach($scope.upCheck,function(value2,index){
if(value.id == value2.threadID)
{
$scope.upDisabled[value.id] = true;
$scope.downDisabled[value.id] = false;
}
})
})
angular.forEach($scope.threads,function(value,index){
angular.forEach($scope.downCheck,function(value2,index){
if(value.id == value2.threadID)
{
$scope.downDisabled[value.id] = true;
$scope.upDisabled[value.id] = false;
}
})
})
}
$scope.loadVotes();
$scope.loadThreads();
As for the server side (PHP with Laravel Framework):
public function upvoteThread($id, $token)
{
$thread = Thread::find($id);
$score = $thread->score;
$score = $score + 1;
$thread->score = $score;
$thread->save();
$voted = ThreadVote::where('threadID','=',$id)->where('token','=',$token)->get();
if($voted->isEmpty())
{
$upVote = new ThreadVote;
$upVote->threadID = $id;
$upVote->token = $token;
$upVote->upVote = 'true';
$upVote->downVote = 'false';
$upVote->save();
}
else
{
DB::table('thread_votes')
->where('threadID', '=', $id)
->where('token','=',$token)
->update(array('upVote' => 'true', 'downVote' => 'false')
);
}
return Response::json(array('status'=>1))->setCallback(Input::get('callback'));
}
public function getUpVotes($token)
{
$votes = ThreadVote::where('token','=',$token)
->where('upVote','=','true')
->select('threadID','upVote')
->get();
return Response::json($votes)->setCallback(Input::get('callback'));
}
...Similar downVote Function...
So as it stands. When the button is pushed, it saves the user's token, threadID, and vote to the database. When the view is loaded, that information, based on the token and threadID is loaded as a JSON array, associated with the Thread array and if a threadID and thread.id matches, it's pushed into the up/downdisabled scope as "threadID":bool ("1":true for example).
I'll recommand you to implement a DB if you manage huge volume of post.
I personnaly use localStorage for several preferences not for storing a db.
Therefore, if you target only for ios / android, I recommand you https://github.com/litehelpers/Cordova-sqlite-storage
If you target windows phone 8.1, the implementation is not trivial and I'm facing some issues regarding the structure of WindowsPhone & C++ compilation librairy ( more details here : https://issues.apache.org/jira/browse/CB-8866 )