WEBINAR PREVIEW: STEP UP YOUR CUSTOMER JOURNEY

Think back to the last AMAZING brand experience you had. That wasn’t an accident. Someone or some team carefully crafted that experience from start to finish, and they did good enough work that it impacted you. Now think back to a HORRIBLE brand experience you had. Someone or some team haphazardly (if at all) “crafted” that experience – with a lack of customer empathy.

Great brand, service or product experiences don’t just happen. They’re driven by forces ranging from basic intuition to highly tuned, vetted, and researched strategies.

That’s why we’re kicking off a free webinar series called “The Extra Mile: Step Up Your Customer Journey.” Watch for online registration, coming soon!

Come join me and Andrew Richburg, our EVP of Marketing, for the most comprehensive and entertaining customer journey webinar you’re bound to encounter. It all starts Tuesday, September 16. From origins and best practices to research, execution and implementation, we have lots of experience (and even more opinions) to share. (Think “Comedians In Cars Getting Coffee,” but without coffee. The cars. Or the professional-grade comedy.)

Planning, fielding, collecting, analyzing, and creating customer journeys are really the core of why I love marketing research. Why are those journeys so important?

Reason #1: Mass Scaling & Consistency

Great brand experiences have been around long before our current technology and methods. But now we can use science, technologies, principles and strategies to mass-produce them. They make it easier to craft, lean, and scale these naturally occurring experiences. Just as Disney found a way to build an experience around imagination and create (and monetize) memories on a massive scale, other companies are using “experience” to define, create value, and differentiate their brands. Again, creating great experiences is not impossible without a prescribed methodology. But using proper tools and guidelines enable a company can do it consistently – and on a much bigger scale.

Reason #2: Higher Competition & Expectations

We’ve reached a point where creating and elevating customer experience is no longer a unique feature of most brands. In entire industries, it’s just the ticket to entry. Take something as simple as packaging. Unpacking a new iPhone used to be one of the highlights of my purchase. Now great packaging is expected and what I used to consider “normal” seems lazy, and other brands in other industries are catching on.

Reason #3: Making People the Equation

Many companies create a product or service, then figure out how to sell it. The customer as an individual (not just a purchaser) becomes an afterthought. We tend to treat our customers like buyers first, people second. The exercise of customer journey mapping reverses that equation and assumes that your customers are people (novel, right?). And it serves as a foundation and roadmap for the innovation required to meet their needs.

That being said, having a “customer journey” won’t do much of anything by itself. It won’t meet customer needs, it doesn’t flip a switch to turn your company into a customer-centric culture or magically change the way your customers feel about you. It’s a tool – and it’s only worthwhile if you turn it into insights and action.

Stay tuned for my next post where I’ll dig into the benefits and limitations of creating a customer journey map. We’ll also have weekly blogs leading up to the webinar, so if you have any questions or comments, please reply right here. I’d love to hear from you!

Posted in Technology | Tagged , , | Leave a comment

A RECIPE FOR SAVING A PDF AS AN ATTACHMENT – SALESFORCE

So you are on a detail page in Salesforce and you want to save of the some of the details of that page in a PDF and then save that PDF as an attachment.  How do you do that?  We just need the right ingredients and the recipe will come out just right.

We need…
1) A Custom Button
2) A Visualforce Page
3) An Apex class that serves as an extension controller

We have seen this type of setup before in many scenarios.  The custom button on the detail page is going to call the Visualforce Page, which will trigger the business logic in the Apex class, and then the class will redirect the user back to the original page.

So let’s run through the recipe.  We will need all of the ingredients from above, but we will use them in reverse order.

1)  Create an Apex class that can save the PDF as an attachment and also re-direct the user back to the starting page.  Let’s assume that we are going to use a Standard Controller so our Apex class will end up being used as an extension.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public with sharing class AttachPDFTerryTest {
    public Account accountItem{get;set;}
    public string idVal{get;set;}
    public string doSave{get;set;}
      
    public AttachPDFTerryTest(ApexPages.StandardController stdController){
        
                idVal = (Account)stdController.getId();
        doSave = ApexPages.currentPage().getParameters().get('doSave');
        accountItem = [Select ID, Name
                From Account where ID = :idVal];       
    }
    
    public pageReference savePDF(){
        
      if(doSave =='No'){
        return null;
      }
        
      PageReference pagePdf = new PageReference('/apex/AttachPDFTerryTest');
          pagePdf.getParameters().put('id', idVal);
          pagePdf.getParameters().put('doSave', 'No');
          Blob pdfPageBlob;
          pdfPageBlob = pagePdf.getContentAsPDF();
                
          Attachment a = new Attachment();
          a.Body = pdfPageBlob;
          a.ParentID = idVal;
          a.Name ='TerryTestAttach1.pdf';
          a.Description ='TestDescription1';
          insert a;
      return new PageReference('/' + idVal);
    }
}

Notice the ‘doSave’ variable on the page.  This allows us to load the page internally in order to save the attachment.  We do not want this insert logic of the attachment to run when we load the page internally.

The return at the bottom of the ‘savePDF()’ method will return the page back to the Account where it originated from.

In our page below we will add the renderAs ‘pdf’ attribute.  In some sense we could just use the ‘getContent()’ method instead of the full ‘getContentAsPDF()’ method since it is already rendered as PDF, but it does make sure we always get a PDF in the end.

2) Create a test class for the class created in #1
Always try to test your class out before attaching it to the page.  It has to be done anyway so when you finally do get to attaching it to the controller you will have much more confidence that your business logic will function properly the first time.

3) Create a Visualforce Page that will use the class created in step #1.
The Visualforce Page will leverage a Standard Controller so the apex:page tag will look like this:

1
2
<apex:page standardcontroller="Account" extensions="AttachPDFTerryTest" action="{!savePDF}" renderas="pdf">
</apex:page>

The standardController attribute will allow us to use all of the functionality of the standard Controller by simply passing the ID of the Account to the page.  The extensions attribute points to the correct class to use where the business logic is stored.  The action attribute specifies which method should be executed on the controller.  You might think what is the point of having the action attribute when the constructor of the class is going to run and you could do all of your work there.  But in the constructor you are not allowed to do DML actions like Insert, Update or Delete.  In this case we are wanting to insert a new attachment so we must put that logic within the method defined by the action attribute.

4) Create your custom button
You want your custom button to be a detail button on the Account object.  When you specify that you want to open a ‘Visualforce Page’, your page will show up in the drop-down since it is using the Standard Controller for an Account.  It is so nice how those pieces fit together.  Just add your custom button to the desired page layout and you will be set.

The getContentAsPDF() can be hard to use at times because you cannot call it from a trigger or a batch job, but in this use case a simple Standard Controller does the trick.  Sending the PDF or the ID of the attachment to a Web Service or Email Service is another way to get around those limitations of getContentAsPDF().

Hopefully that recipe tastes pretty yummy.  Let me know if there is another recipe you are looking for or if we can help you with your next project at Sundog Interactive.

Thanks!

Posted in Technology | Tagged | Leave a comment

CONTROLLING THE MARGINS AND FOOTERS OF A VISUALFORCE PDF – SALESFORCE

Having a Visualforce Page render as a PDF is pretty straightforward.  You just change therenderAs attribute of the apex:page component to be ‘PDF’.  Pretty slick!

But what if you want to control more about how that PDF is rendered including the footer and the margins?

I tried first in two ways that failed.
1) I tried to do some CSS by using an internal style sheet with a ‘style’ tag right on the page.  That did not work.
2) I also tried to do some CSS with some InLine CSS by using the ‘style’ attribute on some controls.  That also did not work.

If anybody could tell me why I would appreciate it!

So then I tried using an ‘External Style Sheet’ which leverages the apex:stylesheet tag in Visualforce.  It worked!  My CSS was recognized and helped to format the margins and footers appropriately.

The css file itself was uploaded as a Static Resource into Salesforce and then it could be referenced very easily with this notation in the Visualforce page:

Notice that I did not have to hard-code the Static Resource into the value for the apex:stylesheet with $Resource.myStyleSheet.  I can use the ‘resourceFileName’ which is a property on the controller so that I could dynamically pick the style sheet.

The actual style sheet that was uploaded looked like this:
@page{
size:portrait;
margin-left: 0.8cm;
margin-right: 0.8cm;
margin-top: 0.8cm;
margin-bottom: 0.8cm;
@bottom-left{
font-family:Arial, Helvetica, sans-serif;
font-size: 8pt;
content: “Company Name Line 1\ALine 2″;
white-space: pre;
}

@bottom-center{
font-family:Arial, Helvetica, sans-serif;
font-size: 8pt;
content: counter(page) ” of ” counter(pages);
}
@bottom-right{
font-family:Arial, Helvetica, sans-serif;
font-size: 8pt;
content: “Details”;
}
}

Notice that the @bottom-left will appear on two lines since the ‘content:’ string has a \A in it and the white-space: is set to be pre.  As stated here in regards to the ‘white-space: pre’ piece: “Whitespace is preserved by the browser. Text will only wrap on line breaks. Acts like the ‘pre’ tag in HTML”.

Pretty cool!  So now I can produce a PDF and control the footers and margins.  Controlling the headers should not be anything more than adding @top-left, @top-center and @top-right items to the CSS class.

Good luck with your PDF generation!

Posted in Technology | Tagged , , , | Leave a comment

WHY INTERNS MIGHT BE ONE OF YOUR BEST MARKETING STRATEGIES

Interns can’t catch a break sometimes. The biggest stories about them seem to involve why they are suing their bosses or why they shouldn’t run your social media.

If that’s all you think of interns however, you’re selling them short. An intern is great because they bring a fresh perspective, creativity and some excitement for your company that you might have lost over the years. When interns are trusted to explore their ideas, have fun, and advocate for your company very good things can happen.

Take the Tumblr All Soups Considered, run by a group of inters at NPR as a play on popular news program All Things Considered. They post the daily soups available at the NPR cafeteria and their brief culinary reviews. There are lots of nerds for NPR (and lots of people who would like to intern or work there) so it serves as a fun, behind the scenes glimpse at day-to-day life for some of the lucky people on the inside.

Another example that takes it even further is the magazine Intern. It’s an independent publication where all of the content is provided by those currently employed as interns or in otherwise unpaid jobs. The magazine is targeted at young employees and taps into the culture they enjoy. It serves as a way to highlight the talent of workers who are currently at the “bottom of the food chain,” so to speak.

Both examples prove that not only can interns help shape your brand, in some cases they may be able to make your brand entirely. Combine eagerness to work and contribute with a bit of fearlessness and a lot of creativity, and some cool content is bound to appear.

Posted in Technology | Tagged | Leave a comment

SUNDOG SPOTLIGHT: TAMMY

Denver has a new team member! This rock and mineral specimen collector brings just enough experience to keep Andrew in line, all while making sure our Denver colleagues are thriving. Meet Tammy Nelson:

 

Tammy

 

Position at Sundog:
I’m the Office Manager/Executive Assistant of the Denver office. I believe the role of support staff is integral, as their purpose is to make the lives of executives and the team they support easier, enabling them to be more efficient, and work effectively to accomplish their goals.

Work experience: 
I spent the last five years supporting the executive team at Harris Broadcast/Imagine Communication’s Denver office. The prior twelve I supported the Director and entire team at the Chrysler Motors Denver office.

Favorite thing about being a ‘Dogger:
Being a part of a company with such a dynamic future and positive culture

First impression of Sundog:
I’m amazed at how welcoming everyone is. The speed at which new employees are educated about and assimilated into Sundog and it’s culture is astonishing.

Last concert you went to:
Santana at Red Rocks Amphitheater – It was fabulous!

Go-to beverage:
Wine! Or lemon water. I like wine better.

Dream vacation spot:
Greece or Italy

Best spot inside Sundog’s space:
Right where I’m sitting – at the corner of Blake & 19th in downtown Denver

Tell us about your family:
I have two grown kids, three grandkids of the human variety and two of the canine persuasion. I also own a very spoiled Silky Terrier.

Currently obsessing over:
Watermelon – It is summer!

Celebrity crush:
Robert Irving. Have you seen those arms?

And, because sharing is caring, you’ll leave our readers with… 
My grandmother often told me, “You don’t have to look far to count your blessings.” It’s a good reminder to approach life in a thankful manner. She also said, “If you can’t be good, at least be sanitary!” She was a woman of few words but they were meaningful.

Posted in Technology | Tagged , | Leave a comment

DOES YOUR CONTENT BUILD RELATIONSHIPS?

 

“Content builds relationships. Relationships build trust. Trust drives revenue.”
—Andrew Davis

 

As we create content, we obsess over so many considerations: Brand compliance. Our audiences. Internal approvals. Design elements. Style standards. Platforms, devices and channels. Search engine optimization. Deadlines, budgets and processes.

It’s easy to lose sight of perhaps the most crucial factor: Does our content build relationships?

The relationship-building aspects of content are central to a customer’s journey. Whether our audience makes an impulsive decision within minutes, or their journey involves many months of twists and turns, the content they experience is so crucial to forming trust and ultimately driving revenue.

To build relationships, your content must:

  • Close gaps in your audience’s knowledge, understanding or questions.
  • Have clear inward and outward paths.
  • Account for your audience’s preferred learning styles (auditory, kinesthetic or visual).
  • Solve problems and share information.
  • Feel credible, natural and helpful.
  • Be guided by audience needs.

Yes, the capitalization and trademark standards must be followed. Stakeholder approvals are unavoidable. Budgets are finite. That crucial tradeshow or buying season can’t be missed. And Twitter’s character count won’t bend.

Yet none of it matters if our content feels too pushy, doesn’t drive action, misses the underlying need, leaves too many unanswered questions, and ultimately erodes trust.

Posted in Technology | Tagged , , | Leave a comment

CREATING CLASSES AND TRIGGERS IN APEX USING THE TOOLING API

Have you ever or are you now in a situation where you need to create an Apex class or trigger via Apex code and you are looking for a good way to do so?  Then you have come to right place.  This post will outline a simple and easy way to create these files in your Apex code that can be run from anywhere.

If you have looked into this at all you have probably thought that you can just use theApexClass or ApexTrigger class to insert or update your new files.  You would be wrong.  While the class docs say that they support create() and update(), it will not work via the API so there is no good way of doing so while using those classes.  The way around this is to simply call the Tooling API from your Apex code.

How do you do this you ask?  First we need to create a Remote Site Setting for your own instance you are working in.  To get the URL you need to use, simply use Execute Anonymous and grab the log of:

1
System.debug(URL.getSalesforceBaseUrl().toExternalForm());

This just simply uses the URL class to get the base URL.  After the remote site setting is added you are ready to rock with your creation code.  Creation of a trigger will look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
String json ='{ "Name" : "TestAccountTrigger", "TableEnumOrId" : "Account", "Body" : "trigger TestAccountTrigger on Account (before insert) {}" }';
Httprequest req =new HttpRequest();
req.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm() +'/services/data/v27.0/sobjects/ApexTrigger');
req.setMethod('POST');
req.setHeader('Content-Type','application/json');
req.setHeader('Authorization','OAuth ' + UserInfo.getSessionId());
req.setBody(json);
Http httpReq =new Http();
HttpResponse res = httpReq.send(req);
System.debug(res.getBody());

You can use the ApexClass and ApexTrigger classes to determine what fields to use when generating your JSON object to send for creation.  As you can see from our JSON, we are creating a trigger on Account with an empty body.  The class is very similar.  The only real change is some of the fields and then endpoint:

1
2
3
4
5
6
7
8
9
10
11
12
String json ='{ "Name" : "MyTestClass", "Body" : "public class MyTestClass{}" }';
Httprequest req =new HttpRequest();
req.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm() +'/services/data/v27.0/sobjects/ApexClass');
req.setMethod('POST');
req.setHeader('Content-Type','application/json');
req.setHeader('Authorization','OAuth ' + UserInfo.getSessionId());
req.setBody(json);
Http httpReq =new Http();
HttpResponse res = httpReq.send(req);
System.debug(res.getBody());

There you have it.  This is how you create a class or trigger from Apex.  One of the only things you need to be cognizant of when doing this is that you cannot create a class or a trigger in a production environment.

If you have any questions on this feel free to comment below.  Happy Coding!!

Posted in Technology | Tagged , , , | Leave a comment

WORKING WITH DYNAMIC MARKERS IN GOOGLE MAPS JS API

Google Maps has been around for quite a while.  As such, when I came across the need to add dynamic markers to a map I did some searching.  My search didn’t really yield what was looking for.  There were a couple of similar situations I had found but nothing that really worked well.

The Need:
I needed a way to have Google Map embedded in a web page with the ability to place markers dynamically on the map with no restriction when it could happen.  The overwhelmingly common answer I found was to simply use a variable (array of arrays) and every time that updates run through the entire initialization code for the map.  While this worked, it was not the best user experience and added a lot of jank.

Below is a simple solution that simply separates marker creation from initialization.  This allows the creation of the markers to be called from the initialization code or anywhere else throughout the page whether it be coordinates from a server response or updated information from a users device location.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
var markerCount = 0;
var map;
//Initializes the map…
function initialize() {
    var myLatlng =new google.maps.LatLng(46.855141, -96.8372664);
    var map_canvas = document.getElementById('map_canvas');
    var map_options = {
        center: myLatlng,
        zoom: 5,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    }
    map =new google.maps.Map(map_canvas, map_options);
}   
//When the window is loaded, run the initialize function to
//setup the map
google.maps.event.addDomListener(window,'load', initialize);   
//This function will add a marker to the map each time it
//is called.  It takes latitude, longitude, and html markup
//for the content you want to appear in the info window
//for the marker.
function addMarkerToMap(lat, long, htmlMarkupForInfoWindow){
    var infowindow =new google.maps.InfoWindow();
    var myLatLng =new google.maps.LatLng(lat, long);
    var marker =new google.maps.Marker({
        position: myLatLng,
        map: map,
        animation: google.maps.Animation.DROP,
    });
    
    //Gives each marker an Id for the on click
    markerCount++;
    //Creates the event listener for clicking the marker
    //and places the marker on the map
    google.maps.event.addListener(marker,'click', (function(marker, markerCount) {
        return function() {
            infowindow.setContent(htmlMarkupForInfoWindow);
            infowindow.open(map, marker);
        }
    })(marker, markerCount)); 
    
    //Pans map to the new location of the marker
    map.panTo(myLatLng)       
}
Posted in Technology | Tagged , , , , | Leave a comment

STARTING A PUSHTOPIC FOR THE STREAMING API IN SALESFORCE

f you have ever used the Streaming API in Salesforce you know that you need to create a PushTopic for users to subscribe to for streaming to work.  Not a big deal right?  It’s just an object and the topics are just records in the object.

If you look at most of the documentation on the Streaming API they suggest using either Execute Anonymous or the Programmers Workbench to insert the records into the PushTopic object to create the PushTopic.  While this works, it could prove to be harmful to the user experience.  What if the PushTopic is removed, then streaming will be disabled.

A good way around this is to check if the PushTopic exists on page load and if it doesn’t, create it.  This can be accomplished by either an action method on the page or by using JS Remoting to call a controller method.  Here is an example of a method you would call from the action of an apex:page:

1
2
3
4
5
6
7
8
9
10
11
12
13
//Call this method from an action on the page
public PageReference startPushTopic(){
    List<PushTopic> current = [Select Id, Name From PushTopic Where Name ='My_PushTopic'];
    if (current !=null && current.size() ==0) {
        PushTopic newTopic =new PushTopic();
        newTopic.Name ='My_PushTopic';
        newTopic.Query ='SELECT Id FROM My_Object__c';
        newTopic.ApiVersion =29.0;
        newTopic.NotifyForOperationCreate =true;
        insert newTopic;           
    }
    return null;
}

If you are not using a controller on the page because you are saving space in your view state or are making an optimized site, you can use JS remoting to accomplish this as well which is outlined below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//JS Code when setting up the Streaming API
(function($){
    $(document).ready(function() {
        // Connect to the CometD endpoint
        $.cometd.init({
            url: window.location.protocol+'//'+window.location.hostname+'/cometd/29.0/',
            requestHeaders: { Authorization:'OAuth {!$Api.Session_ID}'},
            appendMessageTypeToURL :false
       });
       
       MyCustomController.startPushTopic(
           function(result, event){
               //do something with the results         
           }
       );
       $.cometd.subscribe('/topic/My_PushTopic', function(message) {
            console.log('message  ' + message.data.sobject.Location__Latitude__s);
        });
    });
})(jQuery)
//controller code that the JS code calls
public Boolean startPushTopic(){
    List<PushTopic> current = [Select Id, Name From PushTopic Where Name ='My_PushTopic'];
    if (current !=null && current.size() ==0) {
        PushTopic newTopic =new PushTopic();
        newTopic.Name ='My_PushTopic';
        newTopic.Query ='SELECT Id FROM My_Object__c';
        newTopic.ApiVersion =29.0;
        newTopic.NotifyForOperationCreate =true;
        insert newTopic;           
    }
    return true;
}

There you go, a quick and easy way to ensure the PushTopic is up and running when your Streaming API page loads.  The only down side to this is it costs a query each time the page is run but since it is an indexed query it should have a noticeable difference in performance.

Posted in Technology | Tagged , , , , , | Leave a comment

UPLOAD AN IMAGE FROM YOUR MOBILE DEVICE TO SALESFORCE USING CORDOVA

If you have ever built a hybrid mobile application on the Salesforce Platform, you are probably familiar with Cordova.  Cordova allows your application to talk to mobile specific hardware via a JavaScript API.  This allows you the ability to tap into all the device features via JavaScript which allows for cross platform functionality.  In this blog post I will outline using your device’s camera to take a picture and subsequently upload that picture a content item in a Chatter Feed.

The first thing I like to do when building out functionality is to build out the backend.  This makes everything easy for hooking up the front end when the time comes.  For the backend we will just write a JavaScript RemoteAction method for accepting the data from the image.  Since we are going to write a FeedItem, we will need the Id of the parent that we are going to attach to.  Other than the parent Id we will just need the body of the image.  Here is the remote action for inserting the FeedItem.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@RemoteAction
public static String uploadAttachment(String parentId, String contentBody) {
    if(contentBody !=null) {
        try{
            FeedItem post =new FeedItem();
            post.ParentId = parentId;
            post.CreatedById = UserInfo.getUserId();
            post.Body ='Inserted from our app!!';
            post.ContentData = EncodingUtil.base64Decode(contentBody);
            post.ContentFileName ='image.png';
            insert post;
        }catch(Exception e){
            return 'Error:  ' + e;
        }
    }else {
        return 'Error: Image does not exist';
    }
    return 'Success!!!';
}   

Now that the backend is complete we can rock with the front end.  With Cordova, the main object you work with is typically a variable named navigator.  At least this is the case with the auto-generated Salesforce hybrid applications.  To access the devices camera you will need to use the camera object and call the getPicture method:

1
2
3
4
5
6
7
8
9
10
11
//navigator.camera.getPicture( cameraSuccess, cameraError, [ cameraOptions ] );
navigator.camera.getPicture(function(imageData) {
    onPhotoDataSuccess(imageData);
}, function(errorMsg) {
    onPhotoDataError(errorMsg);
}, {
    quality:50,
    correctOrientation:true,
    sourceType: Camera.PictureSourceType.CAMERA,
    destinationType: Camera.DestinationType.DATA_URL
});

This function contains the success function, error function, and optional camera options.  Calling this bit of code from any type of button or onLoad will pull up the devices camera.  As you can see here if it is successful we will call the onPhotoDataSuccess function passing in the imageData from the camera.  Otherwise we just call the error method and let the user know that there was an error.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function onPhotoDataSuccess(imageData){
    My_Controller.uploadAttachment(
        parentId,
        imageData,
        function(result, event) {
            if(event.type ==='exception') {
                console.log("exception");
                console.log(event);
            }else if (event.status) {
                console.log('result:  ' + result);
                if(result.indexOf("Error") != -1){
                    //error
                }else{
                    alert('Uploaded Successfully!!!');
                }
            }else {
                console.log(event.message);
            }
        }
    ); 
}

Here we are simply taking the image data sent back from the camera and calling our RemoteAction method we created earlier.  Keep in mind that you will need a ParentId for the FeedItem.  Also, if you are using Android, you will need to specify permissions for the camera and external storage.

1
2
3
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Simple right?!  Let me know if you have any questions.

Posted in Technology | Tagged , , , , , | Leave a comment