How to pass in custom data to branch.io SDK banner init() call - branch.io

I have a branch smart banner running on my web app using the branch SDK, and I would like to pass in some custom data that will be able to be retrieved when the user downloads our app via the smart banner.
Is there a way to pass in this custom data into the branch.init call?
maybe something like this?
const data = {
custom: 'foo'
}
branch.init(BRANCH_KEY, data)

You can set deep link data, like so:
branch.setBranchViewData({
data: {
'$deeplink_path': 'picture/12345',
'picture_id': '12345',
'user_id': '45123'
}
});
This is only required if custom key-value pairs are used. With Canonical URL, Branch handles this at its end.
For more information, please reference our documentation here: https://docs.branch.io/pages/web/journeys/#deep-linking-from-the-banner-or-interstitial

Related

Handle different markets (language / locale) in Angular 2 application using an Web Api

I could use some advice how I should handle different markets in my angular 2 application. By that I mean a new market (like the German market) where the language is in German, as an example. Right now, I have hardcoded the text inside the html (in english ofc) to make it easy for myself.
An example you see here:
<div class="row">
<h2>Booking number: {{bookingNumber}}</h2>
Your changes has been confirmed.
</div>
I have read something about pipes in angular 2, and i guess I should be using something like that. My problem is, that I really don't know where to start.
Already have an Web Api application created in Visual Studio 2015 which I can use and call.
I'm thinking of making two lists in my Web Api project (one for english, one for german), but there should still be some sort of indicator. By that I mean something like:
BOOKING_NUMBER_TEXT, 'the text in english or german'
CONFIRMATION_TEXT, 'the text...'
That list should have two params like, string string or something like that.. any idea how I could make this?
From my angular 2 application, I'm thinking of calling the api and given it an id (number, lets say 1 and 2, where 1 = english, 2 = germany)
My Web Api finds the correct list and sends it back as JSON.
Then I'm guessing of building a pipe my own where I can filter the words I set in the html. I'm thinking of something like:
<div class="row">
<h2>{{BOOKING_NUMBER_TEXT | 'PIPE NAME' }}: {{bookingNumber}}</h2>
{{CONFIRMATION_TEXT | 'PIPE NAME' }}.
</div>
So when it has name BOOKING_NUMBER_TEXT, it should look into the pipe which has the list object, and take out the text from the right one and place it instead.
Is that a good plan or can you maybe give any advice? (I'm don't want to use any translate angular 2 frameworks, because I have to do different things on each market)
Cheers :)
UPDATE
Ok.. I have created some test data and allowed it to be send via my Web Api. Here is how it looks.
public Dictionary<string, string> createEnglishLocaleKeys()
{
Dictionary<string, string> Locale_EN = new Dictionary<string, string>();
// Account Component
Locale_EN.Add("ACCOUNT_LOGIN_TEXT", "Login");
Locale_EN.Add("ACCOUNT_LOGOUT_TEXT", "Logout");
// Booking Component
Locale_EN.Add("BOOKING_ACTIVE_HEADER_TEXT", "ACTIVE BOOKINGS");
Locale_EN.Add("BOOKING_LOADING_TEXT", "Loading bookings");
Locale_EN.Add("BOOKING_NONACTIVE_HEADER_TEXT", "NON ACTIVE BOOKINGS");
Locale_EN.Add("BOOKING_NOPREBOOKING_TEXT", "You currently do not have any previous bookings");
// Booking List Component
Locale_EN.Add("BOOKING_LIST_BOOKINGNUMBER_TEXT", "Booking number");
Locale_EN.Add("BOOKING_LIST_LEAVING_TEXT", "Leaving");
Locale_EN.Add("BOOKING_LIST_RETURNING_TEXT", "Returning");
Locale_EN.Add("BOOKING_LIST_ROUTE_TEXT", "Route");
Locale_EN.Add("BOOKING_LIST_PASSENGERS_TEXT", "Passengers");
Locale_EN.Add("BOOKING_LIST_VEHICLETYPE_TEXT", "Vehicle type");
// Menu Component
// Passenger Component
// DepartureDate Component
// Confirmation Component
Locale_EN.Add("KEY_NOT_FOUND", "KEY NOT FOUND");
return Locale_EN;
}
Have created an LocaleController which takes a string locale "EN" or "DE" as parameter. Then I'm injecting a service for the controller, which will, based on the locale string choose which method to run (For now I'm only sending back the LocaleEN dictionary).
How can I create an value in my Angular 2 application which should be EN as default and should be changeable?
By changeable, you should be able to set it in the URL or some sort of, like:
localhost:3000/amendment?locale=DE
There are several things here:
You could HTTP content negotiation Conneg - See this link: http://restlet.com/blog/2015/12/10/understanding-http-content-negotiation/) and the Accept-Language to tell the server which messages to return.
You need to wait for messages to be there before displaying the screen with for example: <div ngIf="messages">…</div>
I don't think you need to implement a pipe to display messages if they are defined in a map (key / value): {{messages['SOME_KEY']}}
If messages correspond to list a custom filtering pipe can be implemented and used like that: {{messages | key:'SOME_KEY'}}
The implementation of this pipe could be:
#Pipe({name: 'key'})
export class KeyPipe implements PipeTransform {
transform(value, args:string[]) : any {
// Assuming the message structure is:
// { key: 'SOME_KEY', value: 'some message' }
return value.find((message) => {
return (message.key === args[0]);
});
}
}

Should Durandal url hashes include the id?

Using the HTML Starter Kit example for Durandal 2.0.1.
If I add a route for customers/:id with my own vm and view I can navigate to the page c://temp/index.html#customer/123 and the page displays and in activate I can see the parameter of 123. However, the hash for that page shows as customer/:id Should the router automatically update these hashes to include any passed parameters or is this something I have to do myself?
There may be a baked in fix for this but if you are going to be using the hash and you have the Id or optional Id stuff in there you can use this helper for navigation and to clean up the hash, if needed -
function changeRoute(route) {
var cleanRoute = route.hash;
if (cleanRoute.indexOf(':id') !== -1) {
cleanRoute = cleanRoute.replace(':id', '');
}
return router.navigate('#' + thisRoute);
}
Or you could just as easily add an additional setting on the route to use as the cleaned hash.

How to use store.filter / store.find with Ember-Data to implement infinite scrolling?

This was originally posted on discuss.emberjs.com. See:
http://discuss.emberjs.com/t/what-is-the-proper-use-of-store-filter-store-find-for-infinite-scrolling/3798/2
but that site seems to get worse and worse as far as quality of content these days so I'm hoping StackOverflow can rescue me.
Intent: Build a page in ember with ember-data implementing infinite scrolling.
Background Knowledge: Based on the emberjs.com api docs on ember-data, specifically the store.filter and store.find methods ( see: http://emberjs.com/api/data/classes/DS.Store.html#method_filter ) I should be able to set the model hook of a route to the promise of a store filter operation. The response of the promise should be a filtered record array which is a an array of items from the store filtered by a filter function which is suppose to be constantly updated whenever new items are pushed into the store. By combining this with the store.find method which will push items into the store, the filteredRecordArray should automatically update with the new items thus updating the model and resulting in new items showing on the page.
For instance, assume we have a Questions Route, Controller and a model of type Question.
App.QuestionsRoute = Ember.Route.extend({
model: function (urlParams) {
return this.get('store').filter('question', function (q) {
return true;
});
}
});
Then we have a controller with some method that will call store.find, this could be triggered by some event/action whether it be detecting scroll events or the user explicitly clicking to load more, regardless this method would be called to load more questions.
Example:
App.QuestionsController = Ember.ArrayController.extend({
...
loadMore: function (offset) {
return this.get('store').find('question', { skip: currentOffset});
}
...
});
And the template to render the items:
...
{{#each question in controller}}
{{question.title}}
{{/each}}
...
Notice, that with this method we do NOT have to add a function to the store.find promise which explicitly calls this.get('model').pushObjects(questions); In fact, trying to do that once you have already returned a filter record array to the model does not work. Either we manage the content of the model manually, or we let ember-data do the work and I would very much like to let Ember-data do the work.
This is is a very clean API; however, it does not seem to work they way I've written it. Based on the documentation I cannot see anything wrong.
Using the Ember-Inspector tool from chrome I can see that the new questions from the second find call are loaded into the store under the 'question' type but the page does not refresh until I change routes and come back. It seems like the is simply a problem with observers, which made me think that this would be a bug in Ember-Data, but I didn't want to jump to conclusions like that until I asked to see if I'm using Ember-Data as intended.
If someone doesn't know exactly what is wrong but knows how to use store.push/pushMany to recreate this scenario in a jsbin that would also help too. I'm just not familiar with how to use the lower level methods on the store.
Help is much appreciated.
I just made this pattern work for myself, but in the "traditional" way, i.e. without using store.filter().
I managed the "loadMore" part in the router itself :
actions: {
loadMore: function () {
var model = this.controller.get('model'), route = this;
if (!this.get('loading')) {
this.set('loading', true);
this.store.find('question', {offset: model.get('length')}).then(function (records) {
model.addObjects(records);
route.set('loading', false);
});
}
}
}
Since you already tried the traditional way (from what I see in your post on discuss), it seems that the key part is to use addObjects() instead of pushObjects() as you did.
For the records, here is the relevant part of my view to trigger the loadMore action:
didInsertElement: function() {
var controller = this.get('controller');
$(window).on('scroll', function() {
if ($(window).scrollTop() > $(document).height() - ($(window).height()*2)) {
controller.send('loadMore');
}
});
},
willDestroyElement: function() {
$(window).off('scroll');
}
I am now looking to move the loading property to the controller so that I get a nice loader for the user.

Back Button - Navigating through Viewport

I'am adding content to my application viewport like this:
Ext.Viewport.animateActiveItem(item, {transition})
I'am searching for a way to get "back" to the last view. Is that possible, or does the viewport destroy the last view?
Why not just use the built in history support? You can add an entry to the history object like so:
this.getApplication().getHistory().add(Ext.create('Ext.app.Action', {
url: 'dashboard'
}));
Once you call that function, it will change the application's URL hash. You can grab the event by using routes in your controller... add it to the config like so:
config: {
routes: {
'dashboard': 'showDashboard'
},
control: {
//controls...
}
},
Sencha Touch will recognize the URL change and look to your routes to call a function like so:
showDashboard: function() {
Ext.Viewport.animateActiveItem(item, {transition});
},
Using this method, the native back button will take you back to the previous view, you can also call which view you want to go to etc... view the documentation on the history object here: http://docs.sencha.com/touch/2-0/#!/api/Ext.app.History
Why don't you use the Ext.Viewport.animateActiveItem() on your first panel then ?
I did it here : http://www.senchafiddle.com/#xTZZg
Hope this helps
Ext.app.Action is a private Sencha class so cannot be guaranteed to exist in future releases. A better way is replace ...
this.getApplication().getHistory().add(Ext.create('Ext.app.Action', {
url: 'dashboard'
}));
with this ...
this.getApplication().redirectTo('dashboard');
You can also pass a Model object provided it implements a toUrl() method ...
this.getApplication().redirectTo(myModelObj);
If required, you can now just use the following to go back:
history.back();
Refer to the Touch History Guide:
http://docs.sencha.com/touch/2-2/#!/guide/history_support

How do I get data from a background page to the content script in google chrome extensions

I've been trying to send data from my background page to a content script in my chrome extension. i can't seem to get it to work. I've read a few posts online but they're not really clear and seem quite high level. I've got managed to get the oauth working using the Oauth contacts example on the Chrome samples. The authentication works, i can get the data and display it in an html page by opening a new tab.
I want to send this data to a content script.
i'm having a lot of trouble with this and would really appreciate if someone could outline the explicit steps you need to follow to send data from a bg page to a content script or even better some code. Any takers?
the code for my background page is below (i've excluded the oauth paramaeters and other )
` function onContacts(text, xhr) {
contacts = [];
var data = JSON.parse(text);
var realdata = data.contacts;
for (var i = 0, person; person = realdata.person[i]; i++) {
var contact = {
'name' : person['name'],
'emails' : person['email']
};
contacts.push(contact); //this array "contacts" is read by the
contacts.html page when opened in a new tab
}
chrome.tabs.create({ 'url' : 'contacts.html'}); sending data to new tab
//chrome.tabs.executeScript(null,{file: "contentscript.js"});
may be this may work?
};
function getContacts() {
oauth.authorize(function() {
console.log("on authorize");
setIcon();
var url = "http://mydataurl/";
oauth.sendSignedRequest(url, onContacts);
});
};
chrome.browserAction.onClicked.addListener(getContacts);`
As i'm not quite sure how to get the data into the content script i wont bother posting the multiple versions of my failed content scripts. if I could just get a sample on how to request the "contacts" array from my content script, and how to send the data from the bg page, that would be great!
You have two options getting the data into the content script:
Using Tab API:
http://code.google.com/chrome/extensions/tabs.html#method-executeScript
Using Messaging:
http://code.google.com/chrome/extensions/messaging.html
Using Tab API
I usually use this approach when my extension will just be used once in a while, for example, setting the image as my desktop wallpaper. People don't set a wallpaper every second, or every minute. They usually do it once a week or even day. So I just inject a content script to that page. It is pretty easy to do so, you can either do it by file or code as explained in the documentation:
chrome.tabs.executeScript(tab.id, {file: 'inject_this.js'}, function() {
console.log('Successfully injected script into the page');
});
Using Messaging
If you are constantly need information from your websites, it would be better to use messaging. There are two types of messaging, Long-lived and Single-requests. Your content script (that you define in the manifest) can listen for extension requests:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.method == 'ping')
sendResponse({ data: 'pong' });
else
sendResponse({});
});
And your background page could send a message to that content script through messaging. As shown below, it will get the currently selected tab and send a request to that page.
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {method: 'ping'}, function(response) {
console.log(response.data);
});
});
Depends on your extension which method to use. I have used both. For an extension that will be used like every second, every time, I use Messaging (Long-Lived). For an extension that will not be used every time, then you don't need the content script in every single page, you can just use the Tab API executeScript because it will just inject a content script whenever you need to.
Hope that helps! Do a search on Stackoverflow, there are many answers to content scripts and background pages.
To follow on Mohamed's point.
If you want to pass data from the background script to the content script at initialisation, you can generate another simple script that contains only JSON and execute it beforehand.
Is that what you are looking for?
Otherwise, you will need to use the message passing interface
In the background page:
// Subscribe to onVisited event, so that injectSite() is called once at every pageload.
chrome.history.onVisited.addListener(injectSite);
function injectSite(data) {
// get custom configuration for this URL in the background page.
var site_conf = getSiteConfiguration(data.url);
if (site_conf)
{
chrome.tabs.executeScript({ code: 'PARAMS = ' + JSON.stringify(site_conf) + ';' });
chrome.tabs.executeScript({ file: 'site_injection.js' });
}
}
In the content script page (site_injection.js)
// read config directly from background
console.log(PARAM.whatever);
I thought I'd update this answer for current and future readers.
According to the Chrome API, chrome.extension.onRequest is "[d]eprecated since Chrome 33. Please use runtime.onMessage."
See this tutorial from the Chrome API for code examples on the messaging API.
Also, there are similar (newer) SO posts, such as this one, which are more relevant for the time being.