Meteor JS PubSub based on action - javascript

I need your help or suggestion regarding my refresh function. I have this button called refresh that when clicked it will refresh (rearrange the data sorting based on createdAt field). I have been battling for days trying to get this correctly by resubscribing which i am not sure if it is the correct way or not.
Is there a correct way to resubscribe or re-sorting an a collection on the client when button clicked? Thanks a lot.

Yes, you can do this with following steps:
Pass the sorting type(asc or desc) into router query.
Update the subscribe sorting of server.
You need to also also update your client side find() methods sort, because when data does not change or few document get updated by your re-subscription, SO the oldest data will always come at first.
You can subscribe or re-subscribe collection on either router level or template level. If you are using Flow Rotuer then your re-subscribe will not work simply because flow router is not reactive. I prefer to use subscription at template level. Using Iron router query.
Here is the code sample :
Templete.templeteName.onRendered(function(){
this.autorun(function(){
var sort = {};
if(!Router.current().params.query || Router.current().params.query.sortType == 1 ) {
sort.createdAt = 1;
} else {
sort.createdAt = -1;
}
//You can use this handle to show/hide loader.
var handle = Meteor.Subscribe('subscriptionName', sort);
})
})
Templete.templeteName.helpers({
'data' : function(){
var sort = {};
if(!Router.current().params.query || Router.current().params.query == 1 ) {
sort.createdAt = 1;
} else {
sort.createdAt = -1;
}
return collection.find({},{sort:sort});
}
});
Templete.templeteName.events({
'click .refresh' : function(){
var sortType = value //get the value -1 or 1 from html.
Router.go('routeNaem',{},{query:{sortType:sortType}})
}
});

Related

addPreSearch filter not applying

I am trying to use the addPreSearch function to add a custom filter to a lookup field, but the function does not seem to execute fully before the results of the lookup are displayed. The code for this looks something like this:
function onFieldChange(executionContext) {
var formContext = executionContext.getFormContext();
formContext.getControl("test_code").removePreSearch(testFunctionFilter);
formContext.getControl("test_code").addPreSearch(testFunctionFilter);
}
function testFunctionFilter(executionContext) {
var formContext = executionContext.getFormContext();
var record1 = formContext.getAttribute("test_record1_link").getValue(); //get linked record
var record1FullId, record1Id, stringRecordId, idLength, record1Guid = "0";
if (record1 != null) {
record1Id = record1[0].id;
record1Id = record1FullId.slice(1, -1);
stringRecordId = record1FullId.toString();
idLength = stringRecordId.length;
//Guid when retrieved from tablet does not have parenthesis on each end
if (idLength == 36) {
record1Guid = record1FullId;
} else {
record1Guid = recordId;
}
}
var fieldValue;
Xrm.WebApi.retrieveRecord("test_record1", record1Guid, "?$select=test_field1")
.then(function(result1) {
fieldValue = result1.test_field;
var options = generateOptions(executionContext, fieldValue); //creates option string using retrieved fieldValue
Xrm.WebApi.retrieveMultipleRecords("test_record2", options)
.then(function(result) {
var codes = getCodes(result2, fieldValue);
filter = generateFilter(codes, record1Guid); //creates custom filter using provided parameters
console.log(filter); //displays filter correctly
formContext.getControl("test_codelookup").addCustomFilter(filter, "test_coderecord"); //not working?
});
});
}
The filter is generated correctly using the functions used above whose definitions aren't shown. That isn't the issue. I've tried creating a separate test function where I hard coded one of the filters that the function above generated, and the lookup displayed the correct results. The testFunctionFilter should run to completion before the results of the lookup are displayed, correct? Because the filter is logged to the console after the results of the lookup appear. Are the nested asynchronous Xrm.WebApi calls somehow causing the issue? I'm not quite sure what is wrong. Please advise.
You are right. Xrm.WebApi calls are always Asynchronous, which is unusable in this case of adding dynamic filter using addCustomFilter.
You have to use XMLHttpRequest and make that call as Synchronous by setting third parameter as false like below:
var req = new XMLHttpRequest();
req.open("GET", Xrm.Utility.getGlobalContext().getClientUrl() +
"/api/data/v9.0/test_record1?$select=test_field1", false);
In order to work around the async delay, I think you're going to have to reorganise your code:
Add a form OnLoad event and execute the query to retrieve test_field1 and cache the results in a parameter
In the OnChange event, remove the presearch filter, re-execute the query to retrieve test_field1 and update the same parameter (from onload)
In testFunctionFilter use the cached results rather than building the presearch filter from scratch

Firebase functions - Counting children and updating an entry

I have been trying to use Firebase Functions to write a simple method, but I am unfamiliar with JS.
Below is the structure of my Realtime Database
-spots
---is_hidden: false
---likes
------like_id_1: true
---dislikes
------dislike_id_1: true
I am trying to write a simple method that does the following: Whenever an entry is added to dislikes, count the likes and the dislikes.
If the number of dislikes is larger than the number of ( likes + 5 ),
change the value of is_hidden to true
This is my attempt to solving the problem
exports.checkHiddenStatus = functions.database.ref('/spots/{spotid}').onWrite(
(change, context) => {
const collectionRef = change.after.ref;
const isHiddenRef = collectionRef.child('is_hidden');
const likesRef = collectionRef.child('likes');
const dislikesRef = collectionRef.child('dislikes');
if(isHiddenRef.before.val()) return;
let likeCount = likesRef.numChildren();
let dislikeCount = dislikesRef.numChildren();
let isHidden = false;
if( dislikeCount >= (likeCount + 5))
isHidden = true;
if(!isHidden) return;
// Return the promise from countRef.transaction() so our function
// waits for this async event to complete before it exits.
return isHiddenRef.transaction((current) => {
return isHidden;
}).then(() => {
return console.log('Counter updated.');
});
});
Sadly, because I have no experience with JS I keep getting stuck with error messages I don't understand. The most recent being
TypeError: Cannot read property 'val' of undefined
at exports.checkHiddenStatus.functions.database.ref.onWrite (/user_code/index.js:28:28)
Can somebody please help me write this function? Thank you!
It looks like you're trying to treat a database Reference object like a Change object. Change has before and after properties, but a reference does not.
If you have a database reference object, and you want the value of the database at that location, you need to query it with its once() method.
Read more about reading and writing data using the Admin SDK.

Knockout mapping data from server, lost subscriptions

I'm trying to represent multiple selects with its selected values from backend JSON to knockout view model.
And it's needed to retrieve this JSON when each select is changed, first time - all is ok, but if I apply mapping again (ko.mapping.fromJS(test_data, ViewModel)), all subscriptions are lost does anyone know how to avoid this situation?
jsfiddle (I don't know why selects don't have its values, without jsfiddle - all is ok):
http://jsfiddle.net/0bww2apv/2/
$(ViewModel.attributes()).each(function(index, attribute) {
attribute.attribute_value.subscribe(function(name) {
console.log('SUBSCRIBE', name);
var send_data = {};
$(ViewModel.attributes()).each(function (index, attribute) {
send_data[attribute.attribute_name.peek()] = attribute.attribute_value.peek();
if (attribute.attribute_value() === null) {
send_data = null;
return false;
}
});
if (send_data) {
console.log('REQUEST TO BACKEND: ', ko.toJSON(send_data));
ko.mapping.fromJS(test_data, ViewModel);
// subscriptions is lost here !
}
});
});
At last I've solved my own question with knockout.reactor plugin,
If we remove all auxiliary constructions, it will look like:
var ViewModel = ko.mapping.fromJS(test_data);
ko.applyBindings(ViewModel);
ko.watch(ViewModel, { depth: -1 }, function(parents, child, item) {
// here we need to filter watches and update only when needed, see jsfiddle
ko.mapping.fromJS(test_data2, {}, ViewModel);
});
This way we update selects and don't have troubles with subscription recursions.
full version (see console output for details): http://jsfiddle.net/r7Lo7502/

kendo grid template js with remote datasource

I got a table with remote datasource. in one cell I got the userID. Because I want to show the username instead of the user ID I made a custom template function:
function getUserName(pmcreator){
var user = '';
var data = ''
ds_userList.fetch(function(){
var data = this.data();
for(var i = 0, length = data.length; i < length; i++){
if(data[i].uID == pmcreator){
console.log(data[i].uLastname)
user = data[i].uLastname
}
}
});
return user
}
But its not working as it should, the cells stay empty. I got no errors but I see that the remote request to fetch the usernames is not completed before the grid is filled out. I thought the custom function of fetch is waiting for the results to return but it don't seems so.
Any Idea? I find thousends of examples but all with static local data. I need one with both remote, the grid conent and the template data.
This is probably due the fact that when yuo call the dataSource.fetch it fires off an async function, which causes the thread running the template to continue on. According to kendo you will need to return a control, then set the content of that control inside the callback.
Quick sample using Northwind categories...
Here is the template function
function getDetails(e) {
$.getJSON("http://services.odata.org/V3/Northwind/Northwind.svc/Categories", null, function(data) {
var category = data.value.filter(function(item, i) {
return item.CategoryID === e.CategoryID;
});
$("#async_" + e.CategoryID).html(category[0].Description);
});
return "<div id='async_" + e.CategoryID + "'></div>";
}
http://jsbin.com/ODENUBe/2/edit
I kept getting a recursive error maximum call stack when I just tried to fetch the dataSource, so I switched to a simple getJSON, but it should work pretty much the same.

Populate Ember.Select directly from Database

Let me explain my issue, I am trying to populate Ember.Select directly from database.
I have these routes:
this.resource('twod', function() {
this.resource('twoduser', {
path : ':user_id'
});
});
In twoduser, I am displaying a full information about a single user. In that view, I have a Select Box as well, which end user will select and then with a button, he can add the user to a team that he selected from Ember.Select.
I tried to do this,
App.TwoduserController = Ember.ArrayController.extend({
selectedTeam : null,
team : function (){
var teams = [];
$.ajax({
type : "GET",
url : "http://pioneerdev.us/users/getTeamNames",
data : data,
success : function (data){
for (var i = 0; i < data.length; i ++){
var teamNames = data[i];
teams.push(teamNames);
}
}
});
return teams;
}.property()
})
Then in my index.html:
{{view Ember.Select
contentBinding="team"
optionValuePath="teams.team_name"
optionLabelPath="teams.team_name"
selectionBinding="selectedTeam"
prompt="Please Select a Team"}}
But when I do this, for some reason it interferes with Twoduser and I am not able to view the single user.
Furthermore, here's a sample JSON response I will get through the url:
{"teams":[{"team_name":"Toronto Maple Leafs"},{"team_name":"Vancouver Canuck"}]}
Moreover, I am fetching all users using Ajax like this:
App.Twod.reopenClass({
findAll : function() {
return new Ember.RSVP.Promise(function(resolve, reject) {
$.getJSON("http://pioneerdev.us/users/index", function(data) {
var result = data.users.map(function(row) {
return App.Twod.create(row);
});
resolve(result);
}).fail(reject);
});
},
findBy : function(user_id) {
return new Ember.RSVP.Promise(function(resolve, reject) {
var user = App.Twod.create();
$.getJSON("http://pioneerdev.us/users/byId/" + user_id, function(data) {
var result = user.setProperties(data.user);
resolve(result);
}).fail(reject);
});
}
});
Though there's one thing, I have a separate Teams route:
this.resource('teamview', function(){
this.resource('teamviewdetail', {
path : ':team_id'
});
});
Which shows all the teams and a single team when you click on a single team.
Can I use that TeamviewController? or Can I fetch team names from Twoduser Controller and push names to the array as I mentioned before?
More Information:
If I use the way I mentioned, I get this error:
Uncaught TypeError: Object [object Object] has no method 'addArrayObserver'
Here's a working jsfiddle on the issue I am experiencing. You can select "Storyboard" from the Designation & then select the user. That will reproduce the issue.
One more Update: Seems using ObjectController instead of ArrayController issue solves the addArrayObserver issue. But still I can't get the teams in the Ember.Select.
The biggest issue here is that you use Array#push instead of pushObject. Ember needs the special methods in order to be aware of changes. Otherwise, it will continue to think that the array of teams is as empty as when you first returned it. Second biggest issue is that your ajax success call isn't accessing the returned data properly.
Also, optionValuePath and optionLabelPath are relative to the individual select option view, so they should start with content, which is the individual item as set on the view. So: content.team_name

Categories