display only the elements with checked = true - javascript

I have a list of items with the option to checked or unchecked.
<ion-item ng-repeat="sport in sports"
ng-click="toggleSportSelection(sport)">
{{:: sport.name}}
</ion-item>
if those items are unchecked you are unable to see them here
<div ng-show="sport.checked" ng-repeat="sport in sports">
{{sport.name}}
</div>
those items has been saved in a DB every time you unchecked them.
The reason why I am here, is because the default behavior of the items is checked = true so it doesn't matter if they are saved in a DB, if you refresh the page, all the items are set up to checked = true again.
So what can I do in order to avoid that behavior and that the app recognizes once the items are unchecked or checked ?
this is part of the controller
.controller('SportsController', function($scope, SportsFactory,
AuthFactory) {
SportsFactory.getSportChecked(customer).then(function(sportChecked) {
_.each(sports, function(sport) {
var intersectedSports = _.intersection(sport.id, sportChecked),
checkedSportObjects = _.filter(sport, function(sportObj) {
return _.includes(intersectedSports, sportObj);
});
_.each(checkedSportObjects, function(sport) {
$scope.sports.push(sport);
});
});
//here is the part where the default behavior is checked = true
if (sports.length) {
$scope.sports = _.map(sports, function(sport) {
sport.checked = true;
return sport;
});
}
$scope.toggleSportSelection = function(sport) {
var params = {};
params.user = $scope.customer.customer;
params.sport = sport.id;
sport.checked = !sport.checked;
SportsFactory.setSportChecked(params);
};
});
UPDATE
service.js
setSportChecked: function(params) {
var defer = $q.defer();
$http.post(CONSTANT_VARS.BACKEND_URL + '/sports/checked', params)
.success(function(sportChecked) {
LocalForageFactory.remove(CONSTANT_VARS.LOCALFORAGE_SPORTS_CHECKED, params);
defer.resolve(sportChecked);
})
.error(function(err) {
console.log(err);
defer.reject(err);
});
return defer.promise;
},
and the NODEJS part
sportChecked: function(params) {
var Promise = require('bluebird');
return new Promise(function(fullfill, reject) {
console.time('sportChecked_findOne');
SportSelection.findOne({
user: params.user
}).exec(function(err, sportChecked) {
console.timeEnd('sportChecked_findOne');
var newSport;
if (err) {
reject(new Error('Error finding user'));
console.error(err);
}else if (sportChecked) {
newSport = sportChecked.sport || [];
console.log(newSport);
console.time('sportChecked_update');
if (_.includes(sportChecked.sport, params.sport)) {
console.log('Sport already exists');
console.log(sportChecked.sport);
sportChecked.sport = _.pull(newSport, params.sport);
// sportChecked.sport = _.difference(newSport, params.sport);
console.log(sportChecked.sport);
}else {
newSport.push(params.sport);
sportChecked.sport = newSport;
}
SportSelection.update({
user: params.user
},
{
sport: newSport
}).exec(function(err, sportCheckedUpdated) {
console.timeEnd('sportChecked_update');
if (err) {
reject(new Error('Error on sportChecked'));
}else {
fullfill(sportCheckedUpdated);
}
});
if (sportChecked.sport) {
sportChecked.sport.push(params.sport);
console.log('New sport added');
}else {
sportChecked.sport = [params.sport];
}
}else {
console.time('sportChecked_create');
SportSelection.create({
sport: [params.sport],
user: params.user
}).exec(function(err, created) {
console.timeEnd('sportChecked_create');
if (err) {
reject(new Error('Error on sportChecked'));
}else {
fullfill(created);
}
});
}
});
});
},
I am using lodash so I will appreciate if you can assist me with that.
My issue itself is: it doesn't matter if the items are unchecked, once you refresh the page, all the items will be set up to checked = true again.
Someone says that I can use _.difference, but how ? or what can I do? I am here to read your suggestions.

Something like this?
.controller('SportsController', function($scope, SportsFactory) {
// get a list of all sports, with default value false
SportsFactory.getAllSports().then(function(sports){
$scope.sports = sports;
// set all items to unchecked
angular.each($scope.sports, function(sport) {
sport.checked = false;
});
// get a list of checked sports for customer
SportsFactory.getCheckedSports(customer).then(function(checkedSports)
{
// set the sports in your list as checked
angular.each(checkedSports, function(checkedSport){
var sport = _.findWhere($scope.sports, {id: checkedSport.id});
sport.checked = true;
});
});
$scope.toggleSportSelection = function(sport) {
// do your toggle magic here
};
});
In your view use a filter:
<div ng-repeat="sport in sports | filter:{checked:true}">
{{sport.name}}
</div>

Related

While uncheck the checkbox needs to reload the search item

I'm having the search column with checkbox along with folder names. when I click the checkbox of corresponding folder, it will show their items. As well as when I click on multiple checkbox it will show their corresponding items. But when I uncheck the folder, the corresponding items doesn't remove. So I need the hard reload or refresh when I check or uncheck the checkbox or need to clear the cache for every check or uncheck.
Here is my Code:
Checkbox: Core.component.Checkbox.extend({
click: function () {
var ret=null;
var nav = this.get("controller").get('selectedNavigator');
ret = this._super.apply(this, arguments);
var states=null;
Ember.run.schedule('sync', this, function () {
Ember.run.schedule('render', this, function () {
states = this.get('parentView.itemStates');
var values = Object.keys(states).filter(function (key) {
if(states[key]){
return states[key];}
else{return;}
});
if (values.length === 0) {
Core.Action('core:contentHome', {});
} else {
this.set('parentView.model.values',values);
nav.publish();
}
});
});
return ret;
}
}),
For the Publish:
publish: function () {
var currentResultSet = this.get('resultSet'),
ctl = this.get('controller'),
form = ctl.get('formModel'),
resultSet,
data = form.sleep(2000);
if (Object.keys(data).length === 0) {
Core.view.Menu.create({
anchor: $('*[data-class-name="Core.Tab.Content.Controller.NavigationRefresh"]'),
model: [
Core.model.Menu.Item.create({
label: "Please select something to search.",
icon: 'dialog_warning'
})
]
}).show();
return;
}
resultSet = form.send();
ctl.set('loadState', 'loading');
ctl.set('resultSet', Core.model.BlankResultSet.create({
loadState: 'loading',
tabContext: Ember.get(form, 'resultSet.tabContext')
}));
resultSet.fail(function (err) {
ctl.set('loadState', 'loaded');
console.log(currentResultSet);
ctl.set('resultSet', currentResultSet);
}).always(function () {
ctl.set('loadState', 'loaded');
});
},

AngularJS - Get Checkbox Value?

I'm trying to add a function in my JS for a basic ToDo app that I'm working on using Angular Material and I need to know how I can get it to read the value/property of an md-checkbox (whether or not it is ticked).
The reason for this is I'm trying to make an alert appear informing the user that they need to select at least one checkbox if none are currently selected and they click on the Delete button at the bottom.
Anyone know how I could do this?
Codepen: http://codepen.io/anon/pen/QpdpEa.
JS:
var app = angular.module('todoApp', ['ngMaterial']);
function menuController ($scope, $mdDialog) {
var originatorEv;
this.openMenu = function($mdOpenMenu, ev) {
originatorEv = ev;
$mdOpenMenu(ev);
};
};
app.controller('todoController', function($scope, $mdDialog, $mdToast) {
$scope.sortBy = '-addedOn';
$scope.taskList = [
{ name: 'Task 1', completed: false, addedOn: 1488722128000 },
{ name: 'Task 2', completed: false, addedOn: 1488722128000 },
];
$scope.addTask = function() {
if (angular.isUndefined($scope.taskName) || $scope.taskName.length === 0) {
var alert = $mdDialog.alert()
.parent(angular.element(document.querySelector('#popupContainer')))
.clickOutsideToClose(true)
.title('Error')
.textContent('You must enter a task name')
.ok('Close');
$mdDialog.show( alert )
.finally(function() {
alert = undefined;
});
}
else {
$scope.taskList.push({name: $scope.taskName, addedOn: Date.now()});
$scope.taskName = "";
var pinTo = $scope.getToastPosition();
$mdToast.show (
$mdToast.simple()
.textContent('Task Added')
.position(pinTo)
.hideDelay(3000)
)
}
};
$scope.selectAll = function() {
angular.forEach($scope.taskList, function(task) {
task.completed = true;
});
};
$scope.selectNone = function() {
angular.forEach($scope.taskList, function(task) {
task.completed = false;
});
};
$scope.delete = function(ev) {
var confirm = $mdDialog.confirm()
.title ('Are you sure you want to delete the selected tasks?')
.textContent ('Deleted tasks can\'t be recovered.')
.targetEvent (ev)
.ok ('Confirm')
.cancel ('Cancel')
clickOutsideToClose: false;
$mdDialog.show(confirm).then(function() {
var pinTo = $scope.getToastPosition();
$mdToast.show (
$mdToast.simple()
.textContent('Tasks Deleted')
.position(pinTo)
.hideDelay(3000)
)
$scope.status = 'Tasks Deleted';
var i = $scope.taskList.length;
while (i--) {
var task = $scope.taskList[i];
if(task.completed) {
$scope.taskList.splice(i, 1);
}
}
},
function() {
$scope.status = 'Deletion Cancelled';
});
};
function DialogController($scope, $mdDialog) {
$scope.hide = function() {
$mdDialog.hide();
};
$scope.cancel = function() {
$mdDialog.cancel();
};
$scope.answer = function(answer) {
$mdDialog.hide(answer);
};
};
var last = {
bottom: false,
top: true,
left: false,
right: true
};
$scope.toastPosition = angular.extend({},last);
$scope.getToastPosition = function() {
sanitizePosition();
return Object.keys($scope.toastPosition)
.filter(function(pos) { return $scope.toastPosition[pos]; })
.join(' ');
};
function sanitizePosition() {
var current = $scope.toastPosition;
if ( current.bottom && last.top ) current.top = false;
if ( current.top && last.bottom ) current.bottom = false;
if ( current.right && last.left ) current.left = false;
if ( current.left && last.right ) current.right = false;
last = angular.extend({},current);
};
});
app.controller('toastController', function($scope, $mdToast) {
$scope.closeToast = function() {
$mdToast.hide();
}
});
HTML:
<md-card-actions layout="row" class="md-padding">
<md-button ng-click="selectAll()" class="md-raised md-primary">Select All</md-button>
<md-button ng-click="selectNone()" class="md-raised md-primary">Select None</md-button>
<md-button ng-click="delete()" class="md-raised md-warn md-hue-2">Delete</md-button>
</md-card-actions>
You can just iterate over the taskList variable and check if at least one element has property completed with true value.
I've added a custom function, binded to the Show button. If you click on it, you will see in the console true if there's at least one checkbox checked or false if none of the checkboxes is checked.
$scope.show = function(){
console.log($scope.taskList.some(v => v.completed))
}
http://codepen.io/anon/pen/BWpWmw?editors=1010
I've made changes to your code that you can see & run here: http://codepen.io/anon/pen/jBymPd?editors=1010
I'm using the $filter service to get the task(s) that have completed member set to true.
If nothing has been checked, then you can show an alert to at-least select one task to delete. If one or more task is checked, then you just delete them.
The new changes in your code are shown below:
app.controller('todoController', function($scope, $mdDialog, $mdToast, $filter) {
$scope.delete = function(ev) {
var completedTasks = $filter('filter')($scope.taskList, { completed: true}, true);
console.log(completedTasks); // array of completed tasks, can be empty.
if (completedTasks.length > 0) {
console.log('show dialog box to confirm');
// your existing code.
var confirm = $mdDialog.confirm()
.title ('Are you sure you want to delete the selected tasks?')
.textContent ('Deleted tasks can\'t be recovered.')
.targetEvent (ev)
.ok ('Confirm')
.cancel ('Cancel')
clickOutsideToClose: false;
$mdDialog.show(confirm).then(function() {
var pinTo = $scope.getToastPosition();
$mdToast.show (
$mdToast.simple()
.textContent('Tasks Deleted')
.position(pinTo)
.hideDelay(3000)
)
$scope.status = 'Tasks Deleted';
var i = $scope.taskList.length;
while (i--) {
var task = $scope.taskList[i];
if(task.completed) {
$scope.taskList.splice(i, 1);
}
}
},
function() {
$scope.status = 'Deletion Cancelled';
});
} else {
alert('please select at-least one task to delete');
console.log('show alert to check at-least one task');
}
};
});

Meteor Blaze order sub-documents by sub-document property

Profile:
_id: Pe0t3K8GG8,
videos: [
{id:'HdaZ8rDAmy', url:'VIDURL', rank: 2},
{id:'22vZ8mj9my', url:'VIDURL2', rank: 0},
{id:'8hyTlk8H^6', url:'VIDURL3', rank: 1},
]
The profile is displayed together with the list of videos. I have a Drag & Drop which updates the videos rank using a Server Method.
1) the database updates correctly on Drop.
2) To sort the videos Array - I declare a helper on the Profile Template and SORT the videos array based on a custom comparison function.
Template.Profile.helpers({
'videosSorted': function(){
let videos = (this.videos);
let videosSorted = videos.sort(function(a, b) {
return parseFloat(a.rank) - parseFloat(b.rank);
});
return videosSorted;
}
});
Problem:
A) In Blaze the {{#each videosSorted}} does not reactively update.
If I F5 refresh then i can see the new order.
I think the issue is because I am providing videosSorted which does not update on changes to the document in the db.
How can I make videosSorted reactive?
Update:
All related code:
Iron Router Controller - I subscribe and set the data context for the layout
ProfileController = RouteController.extend({
subscriptions: function() {
this.subscribe('profile',this.params.slug).wait();
},
data: function () {
//getting the data from the subscribed collection
return Profiles.findOne({'slug':this.params.slug});
},
})
Publication:
Meteor.publish('profile', function (slug) {
const profile = Profiles.find({"slug":slug});
if(profile){
return profile;
}
this.ready();
});
The Profile HTML template:
<template name="Profile">
<ul class="sortlist">
{{#each videosSorted}}
{{> Video}}
{{/each}}
</ul>
</template>
I am using mrt:jquery-ui - sortable function
Template.Profile.onRendered(function () {
thisTemplate = this;
this.$('.sortlist').sortable({
stop: function(e, ui) {
el = ui.item.get(0);
before = ui.item.prev().get(0);
after = ui.item.next().get(0);
if(!before) {
newRank = Blaze.getData(after).rank - 1
} else if(!after) {
newRank = Blaze.getData(before).rank + 1
}
else {
newRank = (Blaze.getData(after).rank +
Blaze.getData(before).rank) / 2
}
let queryData = {
_id: thisTemplate.data._id, //the id of the profile record
videos_objId: Blaze.getData(el).objId, //the id of the sub document to update
new_rank: newRank //the new rank to give it
};
//Update the sub document using a server side call for validation + security
Meteor.call("updateVideoPosition", queryData, function (error, result) {
if(!result){
console.log("Not updated");
}
else{
console.log("successfully updated Individual's Video Position")
}
});
}
})
});
And finally the Meteor method that does the updating
'updateVideoPosition': function (queryData){
let result = Individuals.update(
{_id: queryData._id, 'videos.objId': queryData.videos_objId },
{ $set:{ 'videos.$.rank' : queryData.new_rank } }
)
return result;
}
Note :
As i mentioned - the database updates correctly - and if i have an Incognito window open to the same page - i see the videos reactivly (magically !) switch to the new order.
The schema
const ProfileSchema = new SimpleSchema({
name:{
type: String,
}
videos: {
type: [Object],
optional:true,
},
'videos.$.url':{
type:String,
},
'videos.$.rank':{
type:Number,
decimal:true,
optional:true,
autoform: {
type: "hidden",
}
},
'videos.$.subCollectionName':{
type:String,
optional:true,
autoform: {
type: "hidden",
}
},
'videos.$.objId':{
type:String,
optional:true,
autoform: {
type: "hidden",
}
}
});
I came up with really crude solution, but I don't see other options right now. The simplest solution I can think of is to rerender template manually:
Template.Profile.onRendered(function () {
var self = this;
var renderedListView;
this.autorun(function () {
var data = Template.currentData(); // depend on tmeplate data
//rerender video list manually
if (renderedListView) {
Blaze.remove(renderedListView);
}
if (data) {
renderedListView = Blaze.renderWithData(Template.VideoList, data, self.$('.videos-container')[0]);
}
});
});
Template.VideoList.onRendered(function () {
var tmpl = this;
tmpl.$('.sortlist').sortable({
stop: function (e, ui) {
var el = ui.item.get(0);
var before = ui.item.prev().get(0);
var after = ui.item.next().get(0);
var newRank;
if (!before) {
newRank = Blaze.getData(after).rank - 1
} else if (!after) {
newRank = Blaze.getData(before).rank + 1
}
else {
newRank = (Blaze.getData(after).rank +
Blaze.getData(before).rank) / 2
}
let queryData = {
_id: tmpl.data._id, //the id of the profile record
videos_objId: Blaze.getData(el).objId, //the id of the sub document to update
new_rank: newRank //the new rank to give it
};
//Update the sub document using a server side call for validation + security
Meteor.call("updateVideoPosition", queryData, function (error, result) {
if (!result) {
console.log("Not updated");
}
else {
console.log("successfully updated Individual's Video Position")
}
});
}
});
});
Template.VideoList.helpers({
videosSorted: function () {
return this.videos.sort(function (a, b) {
return a.rank - b.rank;
});
}
});
And HTML:
<template name="Profile">
<div class="videos-container"></div>
</template>
<template name="VideoList">
<ul class="sortlist">
{{#each videosSorted}}
<li>{{url}}</li>
{{/each}}
</ul>
</template>
Reativeness was lost in your case because of JQuery UI Sortable. It doesn't know anything about Meteor's reactiveness and simply blocks template rerendering.
Probably you should consider using something more adopted for Meteor like this (I am not sure it fits your needs).

Angular custom filter with promise inside

What I am trying to achieve is using a filter that will return success or error from the ret() function. With the code below it returns {}, which is probably its promise.
.filter('postcode', ['$cordovaSQLite', '$q',
function($cordovaSQLite, $q) {
return function(PostCodeID) {
function ret() {
var def = $q.defer();
ionic.Platform.ready(function() {
if (window.cordova) {
var db = $cordovaSQLite.openDB({
name: "msddocapp.db"
});
} else {
var db = window.openDatabase("msddocapp.db", "1", "ES Database", 5 * 1024 * 1024);
}
var query = "select * from PostCode where ServerID = ?";
$cordovaSQLite.execute(db, query, [PostCodeID]).then(function(s) {
if (s.rows.length > 0) {
def.resolve(s.rows.item(0).Title);
}
}, function(e) {
console.log(e);
def.reject(PostCodeID);
})
});
return def.promise;
}
return ret().then(function(s) {
return s;
}, function(e) {
return e;
});
}
}]);
This filter is used for only one ng-repeat, so maybe I can bind a function to ng-repeat like:
HTML
{{getPostName(item.id)}}
Angular.js
function getPostName(id) {
return post[id].name;
}
Based on your comment
I got ID of PostCode in DB need to Get Value of it and put in place of ID like id = 1 then value is 00-000
You need to use a directive in order to make the call to the database and perform the DOM manipulation.
http://www.sitepoint.com/practical-guide-angularjs-directives/
Directive:
angular.directive('postcode', ['$cordovaSQLite', '$q', function($cordovaSQLite, $q){
return {
template: '{{getPostName(item.id)}}',
link: function(scope, elem, attrs) {
scope.getPostName = function(PostCodeID) {
var def = $q.defer();
ionic.Platform.ready(function() {
if (window.cordova) {
var db = $cordovaSQLite.openDB({
name: "msddocapp.db"
});
} else {
var db = window.openDatabase("msddocapp.db", "1", "ES Database", 5 * 1024 * 1024);
}
var query = "select * from PostCode where ServerID = ?";
$cordovaSQLite.execute(db, query, [PostCodeID]).then(function(s) {
if (s.rows.length > 0) {
def.resolve(s.rows.item(0).Title);
}
}, function(e) {
console.log(e);
def.reject(PostCodeID);
})
});
return def.promise.then(function(s) {
return s;
}, function(e) {
return e;
});
};
}
};
}]);
HTML:
<div data-postcode></div>
EDIT:
Since this particular directive is sharing the scope with its parent you just need to edit the template to use whatever you are passing in, i in this case:
HTML
<tr ng-repeat="i in data.contacts">
<td>
<div data-postcode></div>
</td>
</tr>
Directive
template: '{{getPostName(i.id)}}'

Upload images associated to a meteor collection

I'm having a hard time understanding the whole process of uploading images to a certain Meteor collection eg.(the belongs_to and has_one association with rails).
I have a portfolioitem collection, this is the file:
PortfolioItems = new Mongo.Collection('portfolioItems');
ownsDocument = function(userId, doc) {
return doc && doc.userId === userId;
}
PortfolioItems.allow({
update: function(userId, portfolioItem) { return ownsDocument(userId, portfolioItem); },
remove: function(userId, portfolioItem) { return ownsDocument(userId, portfolioItem); },
});
Meteor.methods({
portfolioItemInsert: function(portfolioItemAttributes) {
check(Meteor.userId(), String);
check(portfolioItemAttributes, {
title: String
});
var portfolioItemWithSameTitle = PortfolioItems.findOne({ title: portfolioItemAttributes.title});
if (portfolioItemWithSameTitle) {
return {
portfolioItemExists: true,
_id: portfolioItemWithSameTitle._id
}
}
var user = Meteor.user();
var portfolioItem = _.extend(portfolioItemAttributes, {
userId: user._id,
submitted: new Date()
});
var portfolioItemId = PortfolioItems.insert(portfolioItem);
return {
_id: portfolioItemId
};
}
});
This is the submit.js template for submitting portfolio items:
Template.submit.events({
'submit #submit-form': function(e) {
e.preventDefault();
var portfolioItem = {
title: $(e.target).find('#submit-title').val()
};
Meteor.call('portfolioItemInsert', portfolioItem, function(error, result) {
if (error) {
return alert(error.reason);
}
if(result.portfolioItemExists) {
alert('Title already taken!');
pause();
}
Router.go('portfolioItemPage', {_id: result._id});
});
}
});
Did you give a try to FSCollection? if not i think its a good option to accomplish this.
You can just declare the collection.
I Suggest you to use GridFS.
just run this 2 commands
meteor add cfs:standard-packages
meteor add cfs:gridfs
Declare the collections like any others.
Images = new FS.Collection("Images", {
stores: [new FS.Store.GridFS("Images")]
});
And you can associate the Simple collection with the FSCollection using metadata.
Template.exampe.events({
'click #addImage':function(){
var file = $('#inputPng').get(0).files[0],
fsFile = new FS.File(file);
fsFile.metadata = {
ownerId:Meteor.userId(),
title:$(e.target).find('#submit-title').val()
}
Images.insert(fsFile,function(err,result){
if(!err){
console.log(result)
}
})
}
})
At this moment the README on the fsCollection its empty so I made a little DEMO about this.

Categories

Resources