Rx (RxJS) Url Builder - javascript

I'm looking for a good way to build urlStream using RxJS that takes multiple parameters.
var searchStream = new Rx.ReplaySubject(1);
var pageStream = new Rx.ReplaySubject(1);
var urlStream = new Rx.Observable.create((observer) => {
//What goes here?
//Should output something like http://apiurl.com?page=page&search=search
});
My instinct is to use Rx.Observable.merge(searchStream, pageStream); but after you do that you don't know which one is which parameter.
With the searchStream subject it allows me to use the subject multiple places in application to searchStream.onNext("my search") and have it trigger a refersh of the data. I've seen plenty of examples that use one url parameter but have yet to see an example that using multiple input streams.

How about:
var searchStream = ...
var pageStream = ...
var urlStream = Rx.Observable.combineLatest(searchStream, pageStream, (search, page) => {
return baseUrl + `?search=${search}&page=${page}`;
})
.shareReplay(1);
I would suggest that you not use Subjects directly when creating streams. Likely whatever is triggering the parameter change could just as easily be wrapped in an Observable instead.
For instance your search would likely be attached to some text box whose change event could be wrapped in a fromEvent
//This would create a stream that waits until the user has stopped
//typing for half a second before sending a request to update.
var searchStream = Rx.Observable.fromEvent($textbox, 'keyup')
.map(e => e.target.value)
.debounce(500);

Related

Return an object from an array of objects for a specific URL in JavaScript

I have a somewhat complicated issue. I'm working for a client that has an array of objects available for every lead on their website (e.g. contact form submission, newsletter signup etc.).
I'm currently working in Google Tag Manager to solve this issue. In order to let my client create their own events, I'm setting up a Tag Manager template where he can create these objects themselves.
However, I want to tie a specific object to a specific action. So if he creates the following object:
var obj1 = {name: 'test', page = 'example.com/test'}
I want this object to only work on that specific page. I know how to create this in JavaScript with a number of if/else statements. But I don't want to adjust the code every time he comes with a new action.
These actions use specific 'thank-you' or 'confirmation' pages to trigger an event on. I'm currently working on a way to push one of these objects whenever someone signs up. For example:
var obj1 = {name: 'newsletter', page = 'example.com/thank-you-newsletter'}
var obj2 = {name: 'contact_form', page = 'example.com/sign-up-contact'}
At the moment, there is no way of restructuring this. So, I was thinking the following:
var page = 'example.com/thank-you-newsletter'; //current page
var userSubmittedURL = 'example.com/thank-you-newsletter'; //given by me
list = [];
if (page === userSubmittedURL) {
list.push(obj1)
}
This userSubmittedURL changes all the time, is there a way to create a specifc object for a specifc page without adjusting the code all the time?
The way to do it is to store the page information in another source (like a text file) and then load it dynamically using ajax. Here is an example from w3Schools (https://www.w3schools.com/js/tryit.asp?filename=tryjs_ajax_first)
const xhttp = new XMLHttpRequest();
xhttp.onload = function() {
document.getElementById("demo").innerHTML =
this.responseText;
}
xhttp.open("GET", "ajax_info.txt");
xhttp.send();
In onload, rather than setting an elements innerHTML, you can use this.responseText to get your url

How to check if a container exists in cosmos DB using the node sdk?

I want to check if a container exists and if not, initialize it. I was hoping for something like the following:
const { endpoint, key, databaseId } = config;
const containerName = "container1"
const client = new CosmosClient({ endpoint ,key});
const containerDefinition = getContainerDefinition(containerName);
const db = await createDatabase(client, databaseId);
if (!db.containers.contains(containerName)
{
// Do something
}
The reason I'm not using "createIfNotExists" is because I would need to make a 2nd call to check if the container returned is populated with items or not. The container I'm creating is going to hold settings data which will be static once the container is initially created. This settings check is going to happen per request so I'd like to minimize the database calls and operations if possible.
I tried doing something like:
try
{
db.container(containerName).read();
}
catch(err)
{
if(err.message.contains("Resource Not Found"))
{
// do something
}
}
But that doesn't seem like the right way to do it.
Any help would be appreciated!
I'm not quite clear on why you would need to do this since typically you only need to do this sort of thing once for the life of your application instance. But I would not recommend doing it this way.
When you query Cosmos to test the existence of a database, container, etc., this hits the master partition for the account. The master partition is kind of like a tiny Cosmos database with all of your account meta data in it.
This master partition is allocated a small amount of the RU/s that manage the metadata operations. So if you app is designed to make these types of calls for every single request, it's quite likely you will get rate limited in your application.
If there is some way you can design this such that it doesn't have to query for the existence of a container then I would pursue that instead.
Interesting question. So i think you have few options
Just call const { container } = await database.containers.createIfNotExists({ id: "Container" }); it will be fast probably few milliseconds, since I went via code at looks like it will always try to read from cosmos :( If you want to still check if container exists sdk has methods(But again no real benefits ):
const iterator = database.containers.readAll();
const { resources: containersList } = await iterator.fetchAll();
Create singleton and first time just initialise all your containers so next time you dont call it, sure if you scale each instance will do the same
My favourite, use terraform/armtemplates/bicep to spin up infrastructure so you code wont need to handle that
You can try this code:
async function check_container_exist(databaseId,containerId) {
let exist = false;
const querySpec = {
query: "SELECT * FROM root r WHERE r.id = #container",
parameters: [
{name: "#container", value: containerId}
]
};
const response = await client.database(databaseId).containers.query(querySpec).fetchNext();
if(response.resources[0]){
exist = true;
}
return exist;
}

Data is not added to existing node in database

I have been trying to add data to my database without any luck.
In my code i have made a button when click, it will add data to my users database but it will not add it to the user but it just add the data outside like this:
is it because you cant add data when you have use the createUserWithEmailAndPassword() function?
Can anyone please show me how it is done?
btn.addEventListener("click", function()
{
firebase.auth().onAuthStateChanged(function(user)
{
if (user)
{
var massage = inputText.value;
var ref = database.ref("Users");
var data = {
display: massage
}
ref.push(data);
}
});
});
Whenever you call push() Firebase generates a new unique ID. So to add the new data to the existing node, you should not call push. Instead you need to find a reference to the existing node for that user.
The easiest (and by far most common) way to do this, is to store the user data under the UID of each user.
Users
kHD...NoS
username: "bob"
Also note that there's no reason to put this type of onAuthStateChange listener inside a button click handler. Just attach it from the top-level JavaScript and it will trigger whenever the user signs in or when their auth state changes in any other way.
Alternatively, if the code really must run in response to the button click, there's no real use for a auth state listener and you can just check firebase.auth().currentUser:
btn.addEventListener("click", function()
{
if (firebase.auth().currentUser)
{
var message = inputText.value;
var ref = database.ref("Users");
var data = {
display: massage
}
ref.child(firebase.auth().currentUser.uid).update(data);
}
}
Your code seems correct if you want to insert a new entry in Firebase database (just like your screenshot shows).
But, if you really want to sign up a new user, then you should be using firebase.auth().createUserWithEmailAndPassword() instead.
Finally, if you really want to update an existing node, see Frank response above ;-)
try this. you can change update to set. In your case something like
demo.update("users/KIK...fuA","display","my message");
//REVEALED METHOD TO ADD NODES WITH DATA TO REALTIME DATABASE
//eg, demo.update('mynode','myKey','myValue')
var demo = (function() {
var pub = {};
pub.update = function (node,key,value){
var ref = firebase.database().ref('/');
var obj = {};
obj[key] = value;
ref.child(node).update(obj)
.then(function() {
console.log('Update Ran Successfully');
});
}
//API
return pub;
}());

Functional Javascript BaconJS, how can I push more values to an event stream?

I'm attempting to create a stack of AJAX responses in BaconJS. That processes them in a first in first out fashion, but each 'out' event should wait for user input.
This is where I'm at now: Live JSBin
var pages = Bacon.fromArray([1,2,3])
var next = $("#next").asEventStream('click').map(true);
pages.flatMapConcat(asyncFunction).zip(next).log("responses")
function asyncFunction(page) {
// Simulating something like an AJAX request
return Bacon.later(1000 + (Math.random() * 3000), "Page "+ page)
}
Currently this synchronously outputs an event from the pages EventStream each time that #next is clicked, which the behavior I want.
However, I am unable to figure out how to push more values to the pages EventStream. I have attempted to replace the pages EventStream with a Bus, and pushing values like this (which doesn't work).
var pages = new Bacon.Bus()
pages.push("value")
How do I push more values to an EventStream?
I know this is an OLD post, but bus would work. Just push the number (you had an array of numbers before) into it:
var pages = new Bacon.Bus();
// Bacon.fromArray([1,2,3])
var next = $("#next").asEventStream('click').map(true);
pages.flatMapConcat(asyncFunction).zip(next).log("responses")
function asyncFunction(page) {
// Simulating something like an AJAX request
return Bacon.later(1000 + (Math.random() * 3000), "Page "+ page)
}
pages.push(1);
pages.push(2);
pages.push(3);
I cloned your jsbin and changed it to use bus
As mentioned previously, you could stream the source of the page values using something like fromEvent or from fromBinder

How can I cleanly pull a Parse.Object relation's records when fetching the object?

In the Parse JavaScript guide, on the subject of Relational Data it is stated that
By default, when fetching an object, related Parse.Objects are not
fetched. These objects' values cannot be retrieved until they have
been fetched.
They also go on to state that when a relation field exists on a Parse.Object, one must use the relation's query().find() method. The example provided in the docs:
var user = Parse.User.current();
var relation = user.relation("likes");
relation.query().find({
success: function(list) {
// list contains the posts that the current user likes.
}
});
I understand how this is a good thing, in terms of SDK design, because it prevents one from potentially grabbing hundreds of related records unnecessarily. Only get the data you need at the moment.
But, in my case, I know that there will never be a time when I'll have more than say ten related records that would be fetched. And I want those records to be fetched every time, because they will be rendered in a view.
Is there a cleaner way to encapsulate this functionality by extending Parse.Object?
Have you tried using include("likes")?
I'm not as familiar with he JavaScript API as the ObjC API.. so in the example below I'm not sure if "objectId" is the actual key name you need to use...
var user = Parse.User.current();
var query = new Parse.Query(Parse.User);
query.equalTo(objectId, user.objectId);
query.include("likes")
query.find({
success: function(user) {
// Do stuff
}
});
In general, you want to think about reverse your relationship. I'm not sure it is a good idea be adding custom value to the User object. Think about creating a Like type and have it point to the user instead.
Example from Parse docs:
https://parse.com/docs/js_guide#queries-relational
var query = new Parse.Query(Comment);
// Retrieve the most recent ones
query.descending("createdAt");
// Only retrieve the last ten
query.limit(10);
// Include the post data with each comment
query.include("post");
query.find({
success: function(comments) {
// Comments now contains the last ten comments, and the "post" field
// has been populated. For example:
for (var i = 0; i < comments.length; i++) {
// This does not require a network access.
var post = comments[i].get("post");
}
}
});
Parse.Object's {Parse.Promise} fetch(options) when combined with Parse.Promise's always(callback) are the key.
We may override fetch method when extending Parse.Object to always retrieve the relation's objects.
For example, let's consider the following example, where we want to retrieve a post and its comments (let's assume this is happening inside a view that wants to render the post and its comments):
var Post = Parse.Object.extend("Post"),
postsQuery = new Parse.Query(Post),
myPost;
postsQuery.get("xWMyZ4YEGZ", {
success: function(post) {
myPost = post;
}
).then(function(post) {
post.relation("comments").query().find({
success: function(comments) {
myPost.comments = comments;
}
});
});
If we had to do this every time we wanted to get a post and its comments, it would get very repetitive and very tiresome. And, we wouldn't be DRY, copying and pasting like 15 lines of code every time.
So, instead, let's encapsulate that by extending Parse.Object and overriding its fetch function, like so:
/*
models/post.js
*/
window.myApp = window.myApp || {};
window.myApp.Post = Parse.Object.extend("Post", {
fetch: function(options) {
var _arguments = arguments;
this.commentsQuery = this.relation("comments").query();
return this.commentsQuery.find({
success: (function(_this) {
return function(comments) {
return _this.comments = comments;
};
})(this)
}).always((function(_this) {
return function() {
return _this.constructor.__super__.fetch.apply(_this, _arguments);
};
})(this));
}
});
Disclaimer: you have to really understand how closures and IIFEs work, in order to fully grok how the above works, but here's what will happen when fetch is called on an existing Post, at a descriptive level:
Attempt to retrieve the post's comments and set it to the post's comments attribute
Regardless of the outcome of the above (whether it fails or not) operation, always perform the post's default fetch operation, and invoke all of that operation's callbacks

Categories

Resources