AngularJS Function with ng-if inside ng-repeat - javascript

I have some times that are calculated dynamically and repeat in an ng-repeat like so:
<div class="col-sm-4" ng-repeat="time in scheduling.openTimes">
<label class="label label-default label-time" ng-class="{'active' : scheduling.militaryTime == time.military}" ng-click="scheduling.setTime(time.military)" ng-if="!scheduling.booked(time.military)">
{{time.display}}
</label>
</div>
And the function scheduling.booked() gets called on each label. It should either return true if the time is "booked" or false if not.
I want the time to display if the time is NOT BOOKED. My function looks like so:
scheduling.booked = function(time)
{
ref.child('appointments').once('value', function(snapshot){
snapshot.forEach(function(childSnapshot){
var data = childSnapshot.val();
var sysDate = new Date(scheduling.date);
var appDate = new Date(data.date);
var appTime = data.time.military;
if(appDate.getDay() == sysDate.getDay())
{
if(appTime == time)
{
return true
}
else
{
return false
}
}
else
{
return false
}
})
})
}
It consoles out everything like it should but the label is not hiding? The console shows that is should be.
update
through some research and lots of deleting, I've came up with this. It works and does what I want as long as you only have one appointment. If you have more than one, it duplicates the time slot. How would you make it so it checked if the time was in the array already and skip it if it is?
scheduling.booked = function(time, timeDis) {
ref.child('appointments').once('value', function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var data = childSnapshot.val();
var sysDate = new Date(scheduling.date).getDate();
var appDate = new Date(data.date).getDate();
var appTime = data.time.military;
if(sysDate == appDate)
{
if(appTime == time)
{
$scope.openTimes.push({
'military' : time,
'display' : timeDis,
'disabled' : true
})
}
else
{
$scope.openTimes.push({
'military' : time,
'display' : timeDis,
'disabled' : false
})
}
}
else
{
$scope.openTimes.push({
'military' : time,
'display' : timeDis,
'disabled' : false
})
}
})
});
$timeout(function(){
scheduling.openTimes = $scope.openTimes;
scheduling.timeLoading = false;
}, 1300)
}
I have another function calling this one now, I've ditched the ng-if.

Your function scheduling.booked does not have a return. So it will always return undefined. So when angular interprets ng-if="!scheduling.booked(time.military)" will be ng-if="true" (!undefined equals true). This explains why all records are shown.
I think the following code should work.
scheduling.booked = function(time) {
var booked = false;
ref.child('appointments').once('value', function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var data = childSnapshot.val();
var sysDate = new Date(scheduling.date);
var appDate = new Date(data.date);
var appTime = data.time.military;
if (appDate.getDay() == sysDate.getDay() && appTime == time) {
booked = true;
}
})
});
return booked; // <-- make sure the function has a return value
}

Related

Trying to use sessionStorage in javascript

I'm trying to show a popup window only once per session. In order to achieve that I'm using sessionStorage function. however, the popup is showing up whenever I reload the web page. Can you please let me know where I'm making the mistake.
dialogue = new IMu.App.Dialogue();
dialogue.setHtmlMessage(IMu.string('dialogue-heading'));
dialogue.show({ showDetails: true });
window.sessionStorage.setItem('message','true');
var is_dialogue = window.sessionStorage.getItem('message');
if (is_dialogue != 'true')
{
dialogue.show();
}
Below is the show function
show: function(options, callback)
{
if (typeof(options) == 'function')
{
callback = options;
options = undefined;
}
var test = jQuery('body').children('div.imu-dialogue');
jQuery('body').children('div.imu-dialogue').remove();
var owner = self.owner = jQuery('body').child('div', 'imu-dialogue');
var box = owner.child('div', 'box');
var message = box.child('div', 'message');
if (this.message)
{
var value = this.message.value;
var method = this.message.type;
message[method](value);
}
if (self.details)
{
var details = box.child('div', 'details');
for (var i in self.details)
{
if (! self.details.hasOwnProperty(i))
continue;
var detail = details.child('div', 'detail');
var value = self.details[i].value;
var method = self.details[i].type || 'text';
detail[method](value);
}
var show = box.child('div', 'show-details');
if (! options || options.showDetails !== true)
{
show.text('Details');
details.hide();
}
else
{
details.show();
show.text('I agree');
}
show.on('click', function()
{
self.owner.remove();
});
}
You've got your logic backwards. You need to check if the sessionStorage item has been set first. If it has not been set, show the dialog and then set it.
if (!sessionStorage.getItem('notified')) {
let dialogue = new IMu.App.Dialogue();
dialogue.setHtmlMessage(IMu.string('dialogue-heading'));
dialogue.show({ showDetails: true });
sessionStorage.setItem('notified', 'true');
}
There is no need to check the value of the stored property. Simply testing for it's existence is enough.
Forget the dialogue.show();
If you try in a new tab of your browser the following code:
window.sessionStorage.setItem('message','true');
is_dialogue = window.sessionStorage.getItem('message');
is_dialogue != 'true' // false
refresh the page and run
is_dialogue = window.sessionStorage.getItem('message');
is_dialogue != 'true' // false
You may have something in your code whick clean session storage on mounted or on created ?

Matching text in element with Protractor

I have an element on page. And there could be different text. I am trying to do like (code is below), and it is not printed to console.
this.checkStatus = function () {
var element = $('.message')
browser.wait(EC.visibilityOf(element), 5000).then(function () {
browser.wait(EC.textToBePresentInElement(conStatus, 'TEXT1'), 500).then(function () {
console.log('TEXT1');
})
browser.wait(EC.textToBePresentInElement(element, 'TEXT2'), 500).then(function () {
console.log('TEXT2');
})
browser.wait(EC.textToBePresentInElement(element, 'TEXT3'), 500).then(function () {
console.log('TEXT3');
})
browser.wait(EC.textToBePresentInElement(element, 'TEXT4'), 500).then(function () {
console.log('TEXT4');
})
})
return this;
}
thanks
I see two problems. first, not sure what 'constatus' is? you need to correct that. second, browser.wait will be throwing error/exceptions when it is not able to find matching condition and timeout expires, So, if your first condition doesn't meet, it will throw timeout exception and will never go to second one. Instead, try something like below
var section = "";
this.checkStatus = function () {
var element = $('.message')
browser.wait(EC.visibilityOf(element), 5000).then(function () {
browser.wait(()=>{
if(EC.textToBePresentInElement(element, 'TEXT1')){
section = "Text1";
}
else if(EC.textToBePresentInElement(element, 'TEXT2')) {
section = "Text2";
}
else if(EC.textToBePresentInElement(element, 'TEXT3')) {
section = "Text3";
}
else if(EC.textToBePresentInElement(element, 'TEXT4')) {
section = "Text4";
}
if(section !== "")
return true;
}, 5000).then(()=>{
<here you can do anything based on 'section'>
}
Note - I haven't verified compilation errors.. so check for that.
Not sure what are you up to, but you can join multiple expected conditions with "or":
var conStatus = $('.message');
var containsText1 = EC.textToBePresentInElement(conStatus, 'TEXT1');
var containsText2 = EC.textToBePresentInElement(conStatus, 'TEXT2');
var containsText3 = EC.textToBePresentInElement(conStatus, 'TEXT3');
var containsText4 = EC.textToBePresentInElement(conStatus, 'TEXT4');
browser.wait(EC.or(containsText1, containsText2, containsText3, containsText4), 5000);

Emberjs: Paginating Fixture Data

I'm building a search box that filters through records and looks for any entity that has the specified number in the searchBy category:
MyApp.SearchController = Em.ObjectController.extend({
searchTerm: "",
searchBy: "id",
searchFor: "customer",
results: function(){
if(this.get('searchTerm') !== ""){
var searchObj = {};
searchObj[this.get('searchBy')] = this.get('searchTerm');
var that = this;
return this.store.all(this.get('searchFor'))
.filter(function(entity){
return ('' + entity.get(that.get('searchBy'))).indexOf(that.get('searchTerm')) != -1;
});
} else return [];
}.property('searchTerm', 'searchBy', 'searchFor'),
...
});
However there is a large CPU spike as soon as i hit '1' as it will filter through every record and check each id.
Is there a way to limit the filter so that it only returns the first 10 matches?
There are a few things you can do, first off, throttling/debounce should probably be used here, http://emberjs.com/api/classes/Ember.run.html#method_debounce. Here's an example of debouncing, start typing, it won't start searching until you've stopped typing for at least 500 ms. http://emberjs.jsbin.com/covovaye/2/edit
You don't need to call all, then filter, just call filter and send it a function as the filter. Additionally you can save quite a few calls to get by getting searchBy and searchTerm, then using those variables over and over, instead of calling get over and over.
results: function(){
if(this.get('searchTerm') !== ""){
var searchObj = {},
searchBy = this.get('searchBy'),
searchTerm = this.get('searchTerm');
searchObj[searchBy] = searchTerm;
var that = this;
return this.store.filter(this.get('searchFor'), function(entity){
return ('' + entity.get(searchBy)).indexOf(searchTerm) != -1;
});
} else return [];
}.property('searchTerm', 'searchBy', 'searchFor')
If you really wanted to get the first 10 you could use slice
results: function(){
if(this.get('searchTerm') !== ""){
var searchObj = {},
searchBy = this.get('searchBy'),
searchTerm = this.get('searchTerm');
searchObj[searchBy] = searchTerm;
var that = this;
return this.store.all(this.get('searchFor'))
.toArray()
.slice(0,10)
.filter(function(entity){
return ('' + entity.get(searchBy)).indexOf(searchTerm) != -1;
});
} else return [];
}.property('searchTerm', 'searchBy', 'searchFor')

Meteor JS: obscene amount of data loaded in loop

I have an app that loads a Jobs collection
Deps.autorun(function(){
var onet = Session.get('currentIndustryOnet');
var city_id = Session.get('currentMapArea');
jobsSubscription = Meteor.subscribe('jobs', onet, city_id);
console.log(onet);
if(jobsSubscription.ready) {
Session.set('jobCount', Jobs.find().count());
}
});
Template.selector.events({
'click div.select-block ul.dropdown-menu li': function(e) {
var selectedIndex = $(e.currentTarget).attr("rel");
var val = $('select#industryPicker option:eq(' + selectedIndex + ')').attr('value');
var oldVal = Session.get('currentIndustryOnet');
if(val != oldVal) {
Session.set('jobsLoaded', false);
Session.set('currentIndustryOnet', val);
}
}
});
The console logs 20+ values for what the var onet is. It appears that Meteor.autorun doesn't run just once. Is this normal? If not, how do I fix this to only run once?
Updated:
Jobs = new Meteor.Collection('jobs');
Cities = new Meteor.Collection('cities');
Pagination.style('bootstrap');
Session.setDefault('jobCount', null);
Session.setDefault('jobsLoaded', false);
Meteor.subscribe('cities');
Session.set('jobCount', Jobs.find().count());
Deps.autorun(function(){
var onet = Session.get('currentIndustryOnet');
var city_id = Session.get('currentMapArea');
Meteor.subscribe('jobs', onet, city_id, function onReady(){
Session.set('jobsLoaded', true);
});
Session.set('jobCount', Jobs.find().count());
});
function plotCities() {
console.log("CITIES PLOTTING");
// var jobs = Jobs.find().fetch();
// var addresses = _.chain(jobs)
// .countBy('address')
// .pairs()
// .sortBy(function(j) {return -j[1];})
// .map(function(j) {return j[0];})
// .slice(0, 50)
// .value();
// gmaps.clearMap();
// $.each(_.uniq(addresses), function(k, v){
// var addr = v.split(', ');
// Meteor.call('getCity', addr[0].toUpperCase(), addr[1], function(error, city){
// if(city) {
// var opts = {};
// opts.lng = city.loc[1];
// opts.lat = city.loc[0];
// opts.population = city.pop;
// opts._id = city._id;
// gmaps.addMarker(opts);
// }
// });
// })
}
Template.list.jobs = function() {
plotCities();
return Pagination.collection(Jobs.find({}).fetch());
}
The console.log('CITIES PLOTTING') gets called around 8 times the first time the page loads and then if I switch the Sessioned onet, and the jobs reloads the data, the call is 30+ times
Update 2:
Here is my code:
Session.set('jobsLoaded', false);
Meteor.subscribe('cities');
Session.set('jobCount', Jobs.find().count());
Deps.autorun(function(){
var onet = Session.get('currentIndustryOnet');
var city_id = Session.get('currentMapArea');
Meteor.subscribe('jobs', onet, city_id, function onReady(){
Session.set('jobsLoaded', true);
});
Session.set('jobCount', Jobs.find().count());
});
function plotCities() {
var jobs = Jobs.find().fetch();
var addresses = _.chain(jobs)
.countBy('address')
.pairs()
.sortBy(function(j) {return -j[1];})
.map(function(j) {return j[0];})
.slice(0, 50)
.value();
gmaps.clearMap();
$.each(_.uniq(addresses), function(k, v){
var addr = v.split(', ');
Meteor.call('getCity', addr[0].toUpperCase(), addr[1], function(error, city){
if(city) {
var opts = {};
opts.lng = city.loc[1];
opts.lat = city.loc[0];
opts.population = city.pop;
opts._id = city._id;
gmaps.addMarker(opts);
}
});
})
}
Template.list.jobs = function() {
if(Session.equals('jobsLoaded', true)) {
console.log("LOADED PLOT");
plotCities();
}
return Pagination.collection(Jobs.find({}).fetch());
}
When console.log("LOADED PLOT") is called... the first time it loads 8 times, the second, almost 40...
Deps.autorun rerun whenever a reactive item used inside is updated. You've got three such items in your function: two session variables and .ready() handle. Most probably the last one is causing the multiple rerun. If you're certain that the session variables were not touched during that time, that's the only option.
While I'm not certain about this, .ready() might be invalidated each time a new item is pulled up in the subscription channel. So having this check inside your autorun would result in several initial reruns as the first batch of data is pulled.
Move that check outside of autorun (it's possible as the subscription is visible from outside) and the problem should be solved.
Ah, now it's something else: you're calling plotCities from Template.list.jobs, which is also reactive and get rerun each time something in Jobs.find({}) changes – so again, each time a new initial item is loaded.
You've got a session variable in which you mark that your subscription is ready. Use it to filter the call:
Template.list.jobs = function() {
if(Session.equals('jobsLoaded', true)) plotCities();
return Pagination.collection(Jobs.find({}).fetch());
}

Excel Type Filter popup for Jqgrid

I need to have a filter ( like in Excel spread Sheet) to embedded to the 'jquery' dialog popup. in this case i need to show all the unique values in the column and check box just before that value to select to the user. when user pressed filter button i need to filter only the values that user requested through the check boxes.
Can any one please let me any approach that i must follow.
Thanks in advance for your help and valuable time.
I was able to develop basic grid with excel kind of filter feature. any one who will come across this type of requirement can use this answer as a foundation.
I use this answer from 'Oleg' to embed the filter popup screen to the basic 'jqgrid'.
in the jqgrid page declare this array with the attributes (columns) that needs to display the filter screen popup.
var applyFilterColumnNames = ['Id','Type','custId','UserId'];
and the column model should be as follows -
colModel :[
{name:'Id', index:'Id',hidden: true,sortable: true},
{name:'custId', index:'custId', width:140,align:"left",sortable: true,search : false},
{name:'Type', index:'Type', width:120,align:"left",sortable: true,search : false},
{name:'UserId', index:'UserId', width:150,align:"left",sortable: true,search : false},
],
used that reference answer to embed the filter button function.
gr.closest("div.ui-jqgrid-view").find("div.ui-jqgrid-hdiv table.ui-jqgrid-htable tr.ui-jqgrid-labels > th.ui-th-column > div.ui-jqgrid-sortable")
.each(function () {
var idPrefix = "jqgh_" + gr[0].id + "_";
var idIndex = (this.id).substr(idPrefix.length,this.id.length) ;
if(includeInArray(applyFilterColumnNames,idIndex)){
jq('<button id=btn_'+idIndex+'>').css({float: "right", height: "17px"}).appendTo(this).button({
icons: {
primary: "ui-icon-gear"
},
text: false
}).click(function (e) {
var idPrefix = "jqgh_" + gr[0].id + "_";
// thId will be like "jqgh_list_name"
var thId = jq(e.target).closest('div.ui-jqgrid-sortable')[0].id ;
if (thId.substr(0, idPrefix.length) === idPrefix) {
var colName = thId.substr(idPrefix.length);
//alert('Clicked the button in the column "' + colName + '"');
constructFilter(colName);
return false;
}
});
//}
}
});
Below is the script i used to filter the jqgrid according to the filters
//Variables that use in filtering operation
var originalData = null;
var filteredData;
var selectedFilters = new Object();
var chkBoxElement;
var firstSortColumn;
function constructFilter(columnName){
// for the first initiation of the filter populate current grid data to an array
if(originalData == null || originalData == 'null'){
try{
// this array will hold the initail data set of the grid
originalData = gr.jqGrid('getGridParam','data');
// set the first sorting grid column
firstSortColumn = columnName;
// check if column is associated with a formatter. if so format the originalData values accordingly.
formatGridData(columnName);
}catch(e){}
}
var colData = new Array();
var filterDataSet;
// if current column is equal to initial sorted column set all posible values to the check boxes in the
// filter screen to select. ( since this is the master sorting column and other columns will filter according to that)
if(columnName == firstSortColumn){
filterDataSet = originalData;
}else{
// set current grid data set to show as checkboxes in the filter page
filterDataSet = gr.jqGrid('getCol',columnName,false);
}
for(key in filterDataSet){
// check box element object that will hold the checkbox label and its state ( true / false)
chkBoxElement = new Object();
chkBoxElement.id = getValueFromArray(filterDataSet[key],columnName);
if(typeof(chkBoxElement.id)== 'undefined'){
break;
}
// if this id is saved in previous filtering event checked option will set to true.
if(typeof(selectedFilters[columnName]) != 'undefined'){
if (includeInArray(selectedFilters[columnName],chkBoxElement.id)){
chkBoxElement.selected = true;
}else{
chkBoxElement.selected = false;
}
}
colData.push(chkBoxElement);
}
// removing duplicates
var uniqueValues = removeDuplicates(colData);
// sort the array without duplicate with the custom comparator
uniqueValues.sort(sortComparator);
// open the filter screen. return type will captured in the 'seletedElements' variable as pipe separated string
seletedElements = window.showModalDialog(filterUrl,uniqueValues,"dialogWidth:400px;dialogHeight:250px;center:yes;resizable:no;status:no;help:no;");
if(seletedElements != null && seletedElements != 'null'){
// get selected values to the array
selectedFilters[columnName] = seletedElements.split("|");
}else{
//user just close the popup (using close button) will return without doing anything
return;
}
if(columnName == firstSortColumn){
// refine filter with the non filtered data set
refillGrid(seletedElements,columnName,originalData);
}else{
// send current data set to refine
var currentDataSet = gr.jqGrid('getGridParam','data');
refillGrid(seletedElements,columnName,currentDataSet);
}
}
function formatGridData(columnName){
var isFormatter = gr.jqGrid("getColProp",columnName);
if(typeof isFormatter.formatter !== 'undefined') {
if(jq.isFunction( isFormatter.formatter ) ) {
for(key in originalData){
var plainValue = originalData[key][columnName];
var formattedVal = isFormatter.formatter.call(null,plainValue,null,null,null);
originalData[key][columnName] = formattedVal;
}
}
}
}
function resetFilters(){
for(key in applyFilterColumnNames){
jq("#btn_"+applyFilterColumnNames[key]).button("option", {
//icons: { primary: this.checked ? 'ui-icon-check' : 'ui-icon-closethick' }
icons: { primary: 'ui-icon-gear'}
});
}
gr.jqGrid("setCaption",gridCaption);
refreshGrid(originalData);
originalData = null;
firstSortColumn = null;
selectedFilters = new Object();
}
function refillGrid(seletedElements,columnName,filterDataSet){
var filteredData= new Array();
var elementsArray;
try{
elementsArray = seletedElements.split("|");
}catch(e){
// this exception happens when user simply open the filter screen
// do nothing and close it.
trace('Error in filter splitting -'+e);
return;
}
// When user de-select all check boxes from the popup screen
if(elementsArray == ""){
refreshGrid(originalData);
return;
}
// refine the grid data according to the filters
var mydata = filterDataSet;
for(i=0;i<elementsArray.length;i++){
var filterElement = elementsArray[i];
for(j = 0;j<mydata.length;j++){
if(filterElement==getValueFromArray(mydata[j],columnName)){
filteredData.push(mydata[j]);
}
}
}
// change the button icon to indicate that the column is filtered
changeButtonIcon(columnName);
// update the column header to indicate sort by column
changeGridCaption(columnName);
// fill the grid according to the passed array
refreshGrid(filteredData);
}
function changeGridCaption(columnName){
// get columns name array
var columnNames = gr.jqGrid('getGridParam','colNames');
// get column model array
var colModel = gr.jqGrid('getGridParam','colModel');
var colModelIndex=null;
if (firstSortColumn == columnName){
for(key in colModel){
try{
if (colModel[key].name == firstSortColumn){
colModelIndex = key;
break;
}
}catch(e){}
}
if(colModelIndex != null){
var columnName = columnNames[colModelIndex];
gr.jqGrid("setCaption",gridCaption + " - Filtered based on : "+columnName);
}
}
}
function changeButtonIcon(columnName){
//change the button Icon
jq("#btn_"+columnName).button("option", {
//icons: { primary: this.checked ? 'ui-icon-check' : 'ui-icon-closethick' }
icons: { primary: 'ui-icon-link'}
});
}
function getValueFromArray(obj,columnName){
if(obj !=null && typeof(obj)!='undefined'){
// if obj param is string just return it
if(typeof obj =='string'){
return obj;
}else{
return obj[columnName];
}
}
}
function sortComparator(a,b){
try{
var aId = a.id.toLowerCase();
var bId = b.id.toLowerCase();
if (aId < bId) {return 1}
if (aId > bId) {return -1}
}catch(e){
return 0;
}
}
function includeInArray(arr,obj) {
//alert(arr);
return (arr.indexOf(obj) != -1);
}
function refreshGrid(results) {
gr.jqGrid('clearGridData')
.jqGrid('setGridParam', { data: results })
.trigger('reloadGrid');
}
function removeDuplicates(valueArray){
var arr = {};
for ( i=0; i < valueArray.length; i++ ){
if(valueArray[i].id != null){
arr[valueArray[i].id] = valueArray[i];
}
}
valueArray = new Array();
for ( key in arr ){
valueArray.push(arr[key]);
}
return valueArray;
}
If something wrong here please let me know.this solution is working fine. but i really appreciate the comments in therms of performance and code best practices.

Categories

Resources