How can I include custom variables in AMP analytics? - ruby-on-rails

A few months ago we introduced AMP to our Rails application. Our implementation includes the following:
<amp-analytics type="googleanalytics">
<script type="application/json">
{
"vars": {
"account": <%= ga.profile_code.inspect.html_safe %>
},
"triggers": {
"trackPageview": {
"on": "visible",
"request": "pageview"
}
}
}
</script>
</amp-analytics>
However, we now realise that we are missing some important custom variables that are used in the Google Analytics script for our non-AMP pages. These are set within a script as follows (where _gaq is an array):
<% ga.variables.each do |vars| %>
_gaq.push([ '_setCustomVar', <%= vars[:placement] %>, '<%= vars[:label] %>', '<%= vars[:variable] %>', <%= vars[:scope_number] %> ]);
<% end %>
Is it possible in AMP Analytics to set custom variables without any restriction on the variable names? If so, how?

You should notice that Custom Variables are only available for legacy google analytics tracking. For the latest implementation, you will need to replace your custom variables with custom dimensions instead. You could check the migration guide Here and Here.
After you have made a migration, you can check the implementation of sending custom dimensions and custom metrics in AMP page.
For example, you can send a custom dimension with a pageview by
including the Custom Dimension parameter (or any other parameters you
want to include with the hit) in the extraUrlParams section. This
section can be included at the trigger level for single requests or at
a global level to send the data with all requests.
<amp-analytics type="googleanalytics">
<script type="application/json">
{
"vars": {
"account": "UA-XXXXX-Y"
},
"extraUrlParams": {
"cd3": "AMP"
},
"triggers": {
"trackPageviewWithCustomData": {
"on": "visible",
"request": "pageview"
},
"trackEvent" : {
"on": "visible",
"request": "event",
"vars": {
"eventCategory": "ui-components",
"eventAction": "header-click"
},
"extraUrlParams": {
"ni": "1"
}
}
}
}
</script>
</amp-analytics>

Related

Making a button visible based on number of records in datatable

I am using jquery datatable in asp.net mvc and i want to show a submit button which will be saving the data to the database only if there is atleast one row in the datatable.
I am trying this code, however its not working
<tr id="trbtnSubmit">
<td colspan="9" align="center">
<input type="submit" name="btnSubmit" value="Save"
class="btn btn-edit btn-text" />
</td>
</tr>
<script>
var PopUp, dataTable;
$(document).ready(function () {
dataTable = $("#tblCustomerList").DataTable({
"ajax": {
"url": "/Customer/GetCustomers",
"type": "GET",
"data": "json"
},
"lengthChange": false,
"pageLength": 10,
"columns": [
{ "data": "Number" },
{ "data": "Name" },
{ "data": "fileName" },
{ "data": "mD5Hash" },
{ "data": "dataSizeInGB" },
{
"data": "Id",
"render": function () {
return "<a href='#'><i class='fa fa-eye'></a></i><a href='#' style='margin-left:5px'><i class='fa fa-pencil'></i></a><a href='#' style='margin-left:5px'><i class='fa fa-trash'></a></i>";
},
"orderable": false,
"width": "40px"
},
],
"language": {
"emptyTable": "No Customers , click on <b>New Customer</b> to add Customers"
}
});
var table = $('#tblCustomerList').DataTable();
if (!table.data().any()) {
$('#trbtnSubmit').hide();
} else {
$('#trbtnSubmit').show();
}
});
</script>
Since you didn't specify the version of datatables, I assume it's v1.10.
And there are 2 side notes I want to make before going into your problem:
Difference between .datatable() and .DataTable()
Enable server-side processing
Difference Between .datatable() and .DataTable()
I saw you declared another variable, var table, at the bottom of your sample code to get another instance of DataTables and check if there is any data? You actually don't need to.
.DataTable() returns a DataTables API instance, while .datatable() returns a jQuery object.
So if you intent to make usages on the DataTables APIs after you initialize the table, you can just use the varirable you declared from the beginning, var dataTable since you used .DataTable() way.
Enable Server-side Processing
Server-side processing is enabled by turning on the serverSide option, and configuring the ajax option. You're missing the first one, whose default is false.
So you might need to add serverSide option in your code:
dataTable = $("#tblCustomerList").DataTable({
serverSide: true,
ajax: {
...
},
...
});
Enough said. Now looking at your problem ...
DataTables Callbacks
There are many ways to achieve what you want to do, and I like to use callbacks so that you can configure your DataTables in one place.
There are lots of callbacks you can use, and the one I would use is drawCallback:
dataTable = $("#tblCustomerList").DataTable({
serverSide: true,
...,
language: {
emptyTable: "No Customers , click on <b>New Customer</b> to add Customers"
},
drawCallback: function(settings) {
$('#trbtnSubmit').toggle(settings.aoData.length > 0);
}
});
Hopefully my code is readable enough without any additional explanations :)

How to work with nested data angularjs and rails?

I am working on an rails application to manage and present images to friends and family.
In that application you can have
Events -> Subevents -> EventImages
routes.rb
resources :events do
resources :subevents do
resources :event_images
end
end
The angularjs part/page is starting when a user selects an specific event.
On the event edit page i want to present the subevents and images like that:
Subevent1 -> Upload Images Button
Image1 Image2 Image3 ...
Subevent2 -> Upload Images Button
Image1 Image2 Image3 ...
...
New Subevent Button
So basically i want to present all available subevents and the images inside each subevent on one page (there could be several subevents and several 100 images). The user should be able to add new subevents and to upload or delete images to each subevent and moving images between subevents via drag/drop. But adding/deleting/uploading/mowing is not my problem right now i just mentioned it because it might influence the solution to my problem.
Im using a nested ng-repeat to display all the information on the page
<div class="subevent" ng-repeat="subevent in event.subevents">
<li class="img" ng-repeat="image in subevent.event_images">
</li>
</div>
Im new to the angular world and im having problems now on how to retrieve the data i need for the page mentioned above.
I came up with two ideas so far:
Retrieve all the informations via an api controller in an nested form:
show.json.jbuilder
json.id #event.id
json.subevents #event.subevents do |subevent|
json.id subevent.id
json.name subevent.name
json.event_images subevent.event_images do |event_image|
json.id event_image.id
json.thumb event_image.image({ resize: "150x150" }).url
end
end
Which will give me this:
{
"id": "54d75dd9686f6c2594020000",
"subevents": [
{
"id": "54d75de1686f6c2594030000",
"name": "Test",
"event_images": [
{
"id": "54df3904686f6c41cf0c0000",
"thumb": "/uploads/event_image/54df3904686f6c41cf0c0000/ebd83a10e03f9794f46cda02fdbc84d3.jpg"
},
{
"id": "54df56c5686f6c41cf850100",
"thumb": "/uploads/event_image/54df56c5686f6c41cf850100/ebd83a10e03f9794f46cda02fdbc84d3.jpg"
}
]
}
]
}
And im using restangular to retrieve this information
$scope.event = Restangular.one('api/events','<%= #event.id %>').get().$object;
But this solution doesnt feel right to me. When i start to manipulate the page (uploading new images/deleting images/moving images from one subevent to another) i see myself refreshing the complete page because i see no other way here on how to just delete one image for example without reloading the complete $scope.event to get the updated page.
The other solution which came to my mind but i did not get working so far was to use the nested features of restangular to retrieve all the needed information for my page without having to create a seperate api controller.
$scope.event = Restangular.one("events",'<%= #event.id %>').all("subevents").all("event_images");
I could not find a working solution which would let me iterate over the $scope.event with ng-repeat like i did above and im not sure if this would solve my overall problem.
So the questions i would like to have answered are:
Should i stick to the API controller appreaoch or is there a way to make my second idea working to get rid of the api controller ?
How do i manipulate the images/subevents without having to reload everything ? ( an example of deleting an image on the page would be great )
This answer your second question using your current API
Plunker
app.js
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.event = {
"id": "54d75dd9686f6c2594020000",
"subevents": [
{
"id": "54d75de1686f6c2594030000",
"name": "Test",
"event_images": [
{
"id": "54df3904686f6c41cf0c0000",
"thumb": "/uploads/event_image/54df3904686f6c41cf0c0000/ebd83a10e03f9794f46cda02fdbc84d3.jpg"
},
{
"id": "54df56c5686f6c41cf850100",
"thumb": "/uploads/event_image/54df56c5686f6c41cf850100/ebd83a10e03f9794f46cda02fdbc84d3.jpg"
}
]
}
]
};
});
app.directive('myEvent', function(){
return {
scope: { myEvent: '=' },
template: "<div>{{myEvent.id}}<div my-subevent='subevent' ng-repeat='subevent in myEvent.subevents'></div></div>",
controller: function($scope){
this.removeSubevent = function(e){
$scope.myEvent.subevents.splice($scope.myEvent.subevents.indexOf(e), 1);
};
}
};
});
app.directive('mySubevent', function(){
return {
scope: {mySubevent: '='},
template: "<div>{{ mySubevent.name }} <a href='' ng-click='remove()'>remove subevent</a><div my-subevent-img='img' ng-repeat='img in mySubevent.event_images'></div></div>",
require: '^myEvent',
link: function(scope, ele, attrs, myEventCtrl){
scope.remove = function(){
myEventCtrl.removeSubevent(scope.subevent);
};
},
controller: function($scope){
this.removeImg = function(img){
$scope.mySubevent.event_images.splice($scope.mySubevent.event_images.indexOf(img), 1);
};
}
};
});
app.directive('mySubeventImg', function(){
return {
scope: { mySubeventImg: '=' },
template: "<div><img ng-src='mySubeventImg.thumb'><a href ng-click='remove()'>remove img</a></div>",
require: '^mySubevent',
link: function(scope, ele, attrs, mySubeventCtrl){
scope.remove = function(){
mySubeventCtrl.removeImg(scope.mySubeventImg);
};
}
};
});
index.html
<div my-event="event"></div>

Create custom item in jsTree Context menu

I create a treeview using jsTree with contextmenu in asp.net mvc3.
<div id="divtree">
<ul id="tree">
<li>#Model.Name
#Html.Partial("Childrens", Model)
</li>
</ul>
<script type="text/javascript">
$(function () {
$("#divtree").jstree(
{
"plugins": ["themes", "html_data", "ui", "crrm", "contextmenu"]
});
});
it's works fine.
I want to create a custom item in the context menu. For example create a new menu item. New for create new Employee in the context menu, and insert the employee in DB. I use a jQuery POST function for this task. But how to handle the click event in the Context menu item.
Here's how you could customize the contextmenu plugin:
$("#divtree").jstree({
"plugins": ["themes", "html_data", "ui", "crrm", "contextmenu"],
"contextmenu": {
"items": function ($node) {
return {
"Create": {
"label": "Create a new employee",
"action": function (obj) {
this.create(obj);
}
},
"Rename": {
"label": "Rename an employee",
"action": function (obj) {
this.rename(obj);
}
},
"Delete": {
"label": "Delete an employee",
"action": function (obj) {
this.remove(obj);
}
}
};
}
}
});
Alright, in this example I am only calling the base function inside the click handlers: this.create(obj);, this.rename(obj); and this.remove(obj); where obj will be the node that was clicked.
So now for example if you want to send an AJAX request to the server when a new item is added you could subscribe to the create.jstree event as shown in the demo page of the jsTree documentation:
<script type="text/javascript">
$("#divtree").jstree({
"plugins": ["themes", "html_data", "ui", "crrm", "contextmenu"],
"contextmenu": {
"items": function ($node) {
return {
"Create": {
"label": "Create a new employee",
"action": function (obj) {
this.create(obj);
}
},
"Rename": {
"label": "Rename an employee",
"action": function (obj) {
this.rename(obj);
}
},
"Delete": {
"label": "Delete an employee",
"action": function (obj) {
this.remove(obj);
}
}
};
}
}
})
.bind("create.jstree", function (e, data) {
$.ajax({
url: "#Url.Action("create", "employees")",
type: 'POST',
data: {
"name" : data.rslt.name
},
success: function (result) {
}
});
});
</script>
Inspect the e and data arguments that are passed to the create.jstree event callback. They contain lots of useful information about the newly created node that you could use to send along with the AJAX request.
Inspired by this example you could continue extending it with the remove.jstree and rename.jstree events as shown in the documentation. So when you look at it, all that was needed was to read the documentation. For example I've never used jsTree in my life but 5 minutes was all that it took me to find the example in the documentation and do a quick spike for you. So next time you have a programming related question about some plugin or framework that you are using please put more efforts into reading the documentation first.

Datatable TableTools with bootstrap not working

Got Datatable to work. Now trying to apply the extra Tabletools (so i can export table to csv).
I can see the export to csv. Am i missing something? I have applied(as suggested)
$(document).ready( function () {
$('#example').dataTable( {
"sDom": "<'row-fluid'<'span6'T><'span6'f>r>t<'row-fluid'<'span6'i><'span6'p>>",
"oTableTools": {
"aButtons": [
"copy",
"print",
{
"sExtends": "collection",
"sButtonText": 'Save <span class="caret" />',
"aButtons": [ "csv", "xls", "pdf" ]
}
]
}
} );
} );
I am using the 'jquery-datatables-rails' gem, which it says it supports table tools.
Thank you
I guess your problem is that you miss the flash-object.
If it is 1.91. Add this to your dataTable{( code (you must realize that the path depends on your setup, so this is just an example)
sSwfPath: "DataTables-1.9.1/extras/TableTools/media/swf/copy_csv_xls_pdf.swf",

Rails - using JSON for a timeline

I've used json_builder to generate the JSON file needed for the timeline from timeline.verite.co as it needs to be in a specific format. However, when I load the page, it gets stuck with a white background and a loading gif. It works if I give it a link to some sample data, but not the generated data for the user. The html page (users/1/events) works fine. Anyone have any idea why? I've run out of ideas now!!
UPDATE:
I got the JS to link to a static file with the pasted contents of the JSON from users/1/events.json, and it works fine. So I'm assuming the problem is that the page is blank when the JS tries to fetch it, and only get populated when you actually go to that URL. How do I get around this?
Generated JSON file (got by going to /users/1/events.json):
{
"timeline": {
"headline": "Emily",
"type": "default",
"text": "A Timeline",
"startDate": "1922,10,30",
"date": [
{
"startDate": "2012,11,17",
"endDate": "2012,11,17",
"headline": "My Birthday",
"text": "This is my birthday",
"asset": {
"media": "http://www.youtube.com/watch?v=dePMU8R131s",
"credit": "",
"caption": "Happy Birthday"
}
}
]
}
}
Required syntax:
{
"timeline":
{
"headline":"Stuff People Say",
"type":"default",
"text":"People say stuff",
"startDate":"2012,1,26",
"date": [
{
"startDate":"2012,1,26",
"endDate":"2012,1,27",
"headline":"Stuff Politicians Say",
"text":"<p>In true political fashion, his character rattles off common jargon heard from people running for office.</p>",
"asset":
{
"media":"http://youtu.be/u4XpeU9erbg",
"credit":"",
"caption":""
}
},
{
"startDate":"2012,1,10",
"headline":"Stuff Nobody Says",
"text":"<p>Have you ever heard someone say “can I burn a copy of your Nickelback CD?” or “my Bazooka gum still has flavor!” Nobody says that.</p>",
"asset":
{
"media":"http://youtu.be/f-x8t0JOnVw",
"credit":"",
"caption":""
}
}
]
}
}
controller (relevant bits):
class EventsController < ApplicationController
respond_to :json, :html
def myevents
#events = current_user.events
respond_with #users
end
end
routes:
resources :events do
member do
get 'myevents'
end
end
match 'users/:id/events' => 'events#myevents'
JS to call timeline:
<%= javascript_include_tag "/js/storyjs-embed.js" %>
<script>
$(document).ready(function() {
createStoryJS({
type: 'timeline',
width: '800',
height: '600',
source: '/users/<%= current_user.id %>/events.json',
embed_id: 'my-timeline'
});
});
</script>
I found the answer in the end, the js for the form wasn't reading the JSON file properly. I needed to add a callback.

Resources