I am following tutorial on here: https://docs.pusher.com/chatkit/quick_start/javascript
There is an example how to create user:
const chatkit = new Chatkit.default({
instanceLocator: "YOUR INSTANCE LOCATOR",
key: "YOUR SECRET KEY"
})
chatkit.createUser({
id: "bookercodes",
name: "Alex Booker"
})
However, when I am trying to run this code with my instanceLocator and key it gives me an error in the console:
SCRIPT445: Object doesn't support this action
Nore that I everything else Chatkit related works fine. I am just not able to create the new user.
Setting instanceLocator and key
You must replace the values of instanceLocator and key passed to
new Chatkit.default({
instanceLocator: "?",
key: "?"
})
To find the correct values, go to https://dash.pusher.com/chatkit and select the chatkit app you want to use.
On the next page, click the Credentisals tab as shown below:
Where you see <instanceLocator> in the screenshot you will find the string to use for instanceLocator, and where you see <key> you will find the string to use for key.
Creating user
If you want to create the user { id: "bookercodes", name: "Alex Booker" } as soon as you start the server, just to test that it works, then your code should work after you do as described above.
That's an IE11 error. Which browser are you using? Try Chrome.
Related
I don't have much idea about JavaScript, so I used Algolia's Instant Search for Firebase Github Repository to build my own function.
My function:
exports.indexentry = functions.database.ref('/posts/{postid}/text').onWrite(event => {
const index = client.initIndex(ALGOLIA_POSTS_INDEX_NAME);
const firebaseObject = {
text: event.data.val(),
timestamp: event.data.val(),
objectID: event.params.postid
};
In Algolia indices, with timestamp as the key, I get the same value as in text field, but in Firebase backend timestamp is different. How to fix this?
I tried different statements to get timestamp value but couldn't.
Edit
Expected Outcome:
{
text: "random rext",
timestamp: "time stamp string",
author: "author name",
object ID: "object ID"
}
Actual Outcome
{
text: "entered text",
object ID: "object ID"
}
I'm not real clear about your goal. Event has a timestamp property. Have you tried:
const firebaseObject = {
text: event.data.val(),
timestamp: event.timestamp, // <= CHANGED
objectID: event.params.postid
};
If you want a long instead of string, use Date.parse(event.timestamp)
EDIT 2: Answer can be found here.
Original Answer: What Bob Snyder said about the timestamp event is correct.
There may be other fields as well, for example, author_name that we may need to index, is there a generalized way to do that or do I write separate functions for every field?
If you want a general way to add all fields, I think what you are looking for can be found here. This should give you the right guidance to get what you want, i.e save your whole object into the Algolia index.
EDIT:
index.saveObject(firebaseObject, function(err, content) {
if (err) {
throw err;
}
console.log('Firebase object indexed in Algolia', firebaseObject.objectID);
});
event.data.val() returns the entire firebase snapshot. If you want a specific value in your data you add it after .val() for example if every post has an author stored in your firebase database under they key "author" you can get this value using var postAuthor = event.data.val().author
I've included some samples from my code for those interested. A sample post looks like this:
Then inside my cloud functions I can access data like this:
const postToCopy = event.data.val(); // entire post
const table = event.data.val().group;
const category = event.data.val().category;
const region = event.data.val().region;
const postKey = event.data.val().postID;
I am getting an error which I just cannot seem to debug. I am trying to create a custom activity entity via custom HTML/JavaScript web resource.
The user clicks a button and the following params:
var params = {
'rob_faqid#odata.bind': '/rob_faqs(guid-here)',
'rob_source': 180840000,
'subject': 'Signpost',
'actualstart': new Date(),
'actualend': new Date()
};
Are passed to this URL:
https://dynamicsorg/api/data/v8.2/rob_quickactions/
With the following headers:
xhr.setRequestHeader('OData-MaxVersion', '4.0');
xhr.setRequestHeader('OData-Version', '4.0');
xhr.setRequestHeader('Accept', 'application/json');
xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
xhr.setRequestHeader('Prefer', 'return=representation');
This gives me a HTTP code of 400 (bad request) and this error message:
An undeclared property 'rob_faqid' which only has property annotations in the payload but no property value was found in the payload. In OData, only declared navigation properties and declared named streams can be represented as properties without values.
Interestingly, I get this error whether I use an actual GUID or if I put some gibberish in there (suggesting it is not to do with the value being passed in).
I can create the records manually via the standard form.
I am using the odata.bind elsewhere within the same project with no errors.
After a good night's sleep I realised my error. To set the value of a lookup field, you need to use the relationship scheme name, and not the property name.
Once I changed that, all worked fine.
When you want to set the value of a lookup field during the creation or update of a (new) record via the web API, you have to use either the Schema Name or the Logical Name of the lookup followed by the bind annotation.
For default fields like primarycontactid the logical name has to be used (first column in the screenshot).
For custom fields like rob_FaqId the schema name has to be used (second column in the screenshot).
var params = {
'rob_FaqId#odata.bind': '/rob_faqs(guid-here)',
'rob_source': 180840000,
'subject': 'Signpost',
'actualstart': new Date(),
'actualend': new Date()
};
Screenshot of a solution > entities > your entity > fields:
So the general structure to create a new record with an already set lookup field via the web API is this:
{
"logicalorschemaName#odata.bind": "/relatedentitys(guid)" //don't forget the plural 's'
}
Or another example from the official documentation. How to create a new account record and directly assign an already existing contact as the primary contact.
var newAccountRecordObj = {
"name": "Sample Account",
"primarycontactid#odata.bind": "/contacts(00000000-0000-0000-0000-000000000001)"
}
While the accepted answer is correct in this instance, it doesn't seem to be the whole story. In some cases it's necessary to use <logical name>_<entity name>. For instance when doing a POST sharepointdocumentlocations, I had to use:
"regardingobjectid_contact#odata.bind": "/contacts(xxxx)"
"parentsiteorlocation_sharepointdocumentlocation#odata.bind" "/sharepointdocumentlocations(xxx)"
This may be something to do with the fact that those relationships can point to more than one type of entity, but I haven't found any Microsoft documentation about it.
Alright, so my protractor test works if I'm not using a mock backend, and everything works as expected when I manually test the functionality (even with a mock backend). The only thing that doesn't work is the protractor test with $httpBackend.
I have the following test:
it("should navigate to add employee and add an employee.", function () {
var tableRowsBeforeAdd = element.all(by.repeater("employee in ec.employees")).count();
var button = element(by.className("btn"));
button.click();
expect(browser.getCurrentUrl()).toContain('add');
var jmbgInput = element(by.model("ec.employee.jmbg"));
jmbgInput.sendKeys("9988776655000");
var nameInput = element(by.model("ec.employee.name"));
nameInput.sendKeys("Test name");
var surnameInput = element(by.model("ec.employee.surname"));
surnameInput.sendKeys("Test surname");
var submit = element(by.buttonText("Save"));
submit.click();
expect(browser.getCurrentUrl()).not.toContain('add');
...
Now, the browser opens (the default url points to a list view of employees), click on the correct button and opens the add/edit form for an employee. It enters the correct information into the input boxes, and it clicks on the button, but at that moment it crashes. The expect statement listed at the end of the code above, as well as all other expect blocks after that one fail, since it acts as if the list view didn't load, which it should, according to my service:
employee.$update().then(function() {
employees.push(employee);
$location.path('/');
});
My employee is a $resource service, and I'd avoid listing all the other code, as it's the same code that works when I use a real backend as well as when I manually use the app.
Now, one thing I'd like to add is the function which I run in the appe2e module:
function appe2ePrep($httpBackend, $location) {
$httpBackend.whenGET("app/components/employee/employee-list.html").passThrough();
$httpBackend.whenGET("app/components/employee/employee-detail.html").passThrough();
var employees = [
{jmbg:"1", name: "Mirko", surname: "Ivovkić"},
{jmbg:"2", name: "Nikola", surname: "Tešić"},
{jmbg:"3", name: "Robert", surname: "Stefanović"},
{jmbg:"4", name: "Aleksa", surname: "Trifković"}
];
// All employees
$httpBackend.whenGET(dbEndpoint + "?apiKey=" + appKey).respond(employees);
// adds a new employee
$httpBackend.whenPUT(dbEndpoint + "/9988776655440?apiKey=" + appKey).respond(function (method, url, data) {
return [200];
});
}
From what I can tell there is a problem with the $location, or at least with the route as the page that should load after the click doesn't.
Well, I'm sorry for wasting everyone's time. I supplied the string "9988776655440" when I was expecting a "9988776655000". For some reason the debugger wasn't showing me a bad request, and all it took was to go over my SO post here to realize the strings don't match.
I got a method that is formatting the date property of a message. A user has an array of messages.
user.messages[i].date = formatDate(user.messages[i].date);
// logs the correctly formatted date
console.log(formatDate(user.messages[i].date));
// logs the unformatted date
console.log(user.messages[i].date);
However, when I do it like the following code snippet it works.
user.messages[i] = {
name: user.messages[i].name,
body: user.messages[i].body,
_id: user.messages[i]._id,
date: formatDate(user.messages[i].date)
};
With the help of the comment from #plalx, I found a solution in this thread:
Stubbing virtual attributes of Mongoose model
This is a guess but you could add formatteddate:"" into your user model (or similar) and then try:
user.messages[i].formatteddate = formatDate(user.messages[i].date);
Therefore you are not re-configuring it.
I've used the webOS Ares tool to create a relatively simple App. It displays an image and underneath the image are two labels. One is static, and the other label should be updated with new information by tapping the image.
When I tap the image, I wish to obtain a JSON object via a URL (http://jonathanstark.com/card/api/latest). The typcial JSON that is returned looks like this:
{"balance":{"amount":"0","amount_formatted":"$0.00","balance_id":"28087","created_at":"2011-08-09T12:17:02-0700","message":"My balance is $0.00 as of Aug 9th at 3:17pm EDT (America\/New_York)"}}
I want to parse the JSON's "amount_formatted" field and assign the result to the dynamic label (called cardBalance in main-chrome.js). I know that the JSON should return a single object, per the API.
If that goes well, I will create an additional label and convert/assign the "created_at" field to an additional label, but I want to walk before I run.
I'm having some trouble using AJAX to get the JSON, parse the JSON, and assign a string to one of the labels.
After I get this working, I plan to see if I can load this result on the application's load instead of first requiring the user to tap.
So far, this is my code in the main-assistant.js file. jCard is the image.
Code:
function MainAssistant(argFromPusher) {}
MainAssistant.prototype = {
setup: function() {
Ares.setupSceneAssistant(this);
},
cleanup: function() {
Ares.cleanupSceneAssistant(this);
},
giveCoffeeTap: function(inSender, event) {
window.location = "http://jonathanstark.com/card/#give-a-coffee";
},
jcardImageTap: function(inSender, event) {
//get "amount_formatted" in JSON from http://jonathanstark.com/card/api/latest
//and assign it to the "updatedBalance" label.
// I need to use Ajax.Request here.
Mojo.Log.info("Requesting latest card balance from Jonathan's Card");
var balanceRequest = new Ajax.Request("http://jonathanstark.com/card/api/latest", {
method: 'get',
evalJSON: 'false',
onSuccess: this.balanceRequestSuccess.bind(this),
onFailure: this.balanceRequestFailure.bind(this)
});
//After I can get the balance working, also get "created_at", parse it, and reformat it in the local time prefs.
},
//Test
balanceRequestSuccess: function(balanceResponse) {
//Chrome says that the page is returning X-JSON.
balanceJSON = balanceResponse.headerJSON;
var balanceAmtFromWeb = balanceJSON.getElementsByTagName("amount_formatted");
Mojo.Log.info(balanceAmtFromWeb[0]);
//The label I wish to update is named "updatedBalance" in main-chrome.js
updatedBalance.label = balanceAmtFromWeb[0];
},
balanceRequestFailure: function(balanceResponse) {
Mojo.Log.info("Failed to get the card balance: " + balanceResponse.getAllHeaders());
Mojo.Log.info(balanceResponse.responseText);
Mojo.Controller.errorDialog("Failed to load the latest card balance.");
},
//End test
btnGiveCoffeeTap: function(inSender, event) {
window.location = "http://jonathanstark.com/card/#give-a-coffee";
}
};
Here is a screenshot of the application running in the Chrome browser:
In the browser, I get some additional errors that weren't present in the Ares log viewer:
XMLHttpRequest cannot load http://jonathanstark.com/card/api/latest. Origin https://ares.palm.com is not allowed by Access-Control-Allow-Origin.
and
Refused to get unsafe header "X-JSON"
Any assistance is appreciated.
Ajax is the right tool for the job. Since webOS comes packaged with the Prototype library, try using it's Ajax.Request function to do the job. To see some examples of it, you can check out the source code to a webOS app I wrote, Plogger, that accesses Blogger on webOS using Ajax calls. In particular, the source for my post-list-assistant is probably the cleanest to look at to get the idea.
Ajax is pretty much the way you want to get data, even if it sometimes feels like overkill, since it's one of the few ways you can get asynchronous behavior in JavaScript. Otherwise you'd end up with code that hangs the interface while waiting on a response from a server (JavaScript is single threaded).