0

I am able to store strings, and numbers in Parse, but I am experiencing issues storing images in Parse.

Essentially, a user selects an image from their gallery and that image is inserted inside an image with an id such as:

        <img src="content/profilef.png" id="profilePic1" />
        <img src="content/profile.png" id="profilePic2" />

        <img src="content/profileu.png" id="profilePic3" />

This is what I am trying to grab and store into Parse, I have already create 3 files column in parse.

This is my JavaScript code, everything works beside the images I am trying to store:

function accountCreation(event){
    event.preventDefault();
    var bio = document.getElementById("profileDescription").value;
    var city = document.getElementById("selectCity").value;
    var men = document.getElementById("selectMen").checked;
    var women = document.getElementById("selectWomen").checked;

       var profilePic1 = document.getElementById("profilePic1").value;

                            var profilePic2 = document.getElementById("profilePic2").value;
                            var profilePic3 = document.getElementById("profilePic3").value;





    var user = Parse.User.current();
        user.set("profilePic1", profilePic1);
        user.set("profilePic2", profilePic2);
        user.set("profilePic3", profilePic3);

    user.set("bio", bio);
    user.set("city", city);
    user.set("menPreference", men);
    user.set("womenPreference", women);

    user.save(null, {
        success: function(user) {
            alert("succesfully stored");
        },

        error: function(user, error) {
            alert('error' + error.message);
        }
    });
}

Thanks in advance,

Update: Because I am working with Intel XDK (or phonegap), I cannot use php locally, so I had to host the php code on the cloud., below is the error i get

Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check http://xhr.spec.whatwg.org/.

 failed to create file, src= content/profilef.png, encoded img=
accountCreation.js:56 failed to create file, src= content/profile.png, encoded img=
accountCreation.js:56 failed to create file, src= content/profileu.png, encoded img=

the script

$(function() {

    //Initialize Parse below by using credentials provided for App on Parse 
Parse.initialize("ID", "ID");

// click handlers
    // this watches for clicks to save user data 
    $('#accountCreation').click(function(event){
        event.preventDefault(); // only needed if the clicked element is a link
        accountCreation();
    })




    function accountCreation(){
            $('#container').hide(); // hide the display while we save the info as it will take a few seconds, you should do a loading bar or something here instead

            var user = Parse.User.current(); // get the currently logged in user object
            var bio = $('#profileDescription').val();
            var city = $('#selectCity').val();
            var men = $('#selectMen').is(':checked'); // returns true or false
            var women = $('#selectWomen').is(':checked'); // returns true or false

            // $('.images') retruns an array of elements with the class name "images"
            // loop through each image element
            $('.images').each(function(index, element) {
                  // first we'll need to get the image source 
                  var src = $(element).attr('src');
                  // alone, the source is just a url and not of much use to us
                  // we'll need to take the source and create a base64 encoded string from it
                  // we'll use an ajax call to a small php script to do this
                  var encodedImg;
                  try {
                    $.ajax({
                       type: "POST",
                       url: "http://addo-env.elasticbeanstalk.com/aws/encodeImgToBase64.php", // you may need to adjust this path depending on where you store the file in relation to this file
                       data: 'url='+src,
                       success: function(data){
                         encodedImg = data; // encodedImg is now a base64 encoded string 
                       },
                       async: false 
                       // note the use of `async: false` here
                       // normally the ajax call would run asynchronously in the background  
                       // and the below code would be run immediately, even before the ajax call has finished 
                       // `async: false` stops execution here and forces the ajax call to finish before any other code is run 
                       // this isnt normally a great way to do this since it locks up the page while the funcion is working
                       // but, honestly, this is a save function and its pretty standard for other features on a page to be unavailable while saving data
                       // that said, this could be written better with `promises` but it works as is
                     });
                    var file = new Parse.File("photo.jpg", { base64: encodedImg }); // this part actually saves the image file to parse
                    // From the Docs: Notice in this example that we give the file a name of photo.jpg. You don't need to worry about filename collisions. 
                    // Each upload gets a unique identifier so there's no problem with uploading multiple files named photo.jpg.
                    user.set("image"+index,file); // set this image to the corosponding column on our object 
                  } catch (e) {
                    console.log('failed to create file, src= '+src+', encoded img='+encodedImg)
                  }
            });
            user.set("bio", bio);
            user.set("city", city);
            user.set("menPreference", men);
            user.set("womenPreference", women);
            // save our new 
            user.save(null,{
              success: function(user) { 
                  $('#message').html('Profile Updated!');
                  $('#container').show(); // show the screen again, you should just remove your loading bar now if you used one
              },
              error: function(user, error) {
                  console.log('Failed to create new object, with error code: ' + error.message);
              }
            });
     }

Update 2:

<?php
header('Access-Control-Allow-Origin: *');
if (isset($_POST['url']) ){
    echo base64_encode(file_get_contents($_POST['url']));
}else{
    echo 'Error: No image to encode';
}
?>

This is the PHP code above, it has header access-control allow to allow cross-domain access, without the header, i would get an error. It hosted on aws, and there is the link:

http://addo-env.elasticbeanstalk.com/aws/encodeImgToBase64.php

I cant store it locally because php won't work with phonegap or intel xdk so have to host it on the cloud

7
  • Check out parse.com/docs/js_guide#files , in addition to what @juno_okyo mentions below, you must first save the file itself to parse then, once it's saved you can associate the file with the user object you are saving. I have to go back to work but if you dont have a full answer when I get off later, Ill work up an example for you Commented Mar 6, 2015 at 2:15
  • thank you delighted. I've looked into Juno answer, but the problem it that it just provided me with the string url of the image. I agree i ust save the file to parse, and would greatly appreciate an example Commented Mar 6, 2015 at 4:37
  • any asssitance would greatly be appreciateed Commented Mar 6, 2015 at 14:38
  • sorry, had a long night. Working on that for you now though :) Commented Mar 6, 2015 at 15:26
  • any luck, or any updates. i am really ttying to get over this issue Commented Mar 6, 2015 at 16:49

2 Answers 2

1

Parse.com can't save an image file directly from a url unfortunately. Because you want to get the image from an img tag on the page (rather than say an input where the user uploaded the image), you'll need to use a canvas element to convert the images to base64 encoded strings, save parse files using those strings, then associate the files to your user, and finally save the user object.

I also show you below how to retrieve and display the stored images. The comments should explain most everything.

Additionally, here is a fully working demo so you can see how it works

The jQuery:

// click handler
// this watches for clicks to save user data 
$('#accountCreation').click(function(event){
    event.preventDefault(); // only needed if the clicked element is a link
    accountCreation();
})

function accountCreation(){
    $('#container').hide(); // hide the display while we save the info as it will take a few seconds, you should do a loading bar or something here instead
    var user = Parse.User.current(); // get the currently logged in user object

    // loop through each image element
    var promises = $('.images').map(function(index, element) {
        var deferred = $.Deferred();
        var src = $(element).attr('src');
        var canvas = document.createElement('CANVAS');
        var ctx = canvas.getContext('2d');
        var img = new Image;
        img.crossOrigin = 'Anonymous';
        img.onload = function(){
            canvas.height = img.height;
            canvas.width = img.width;
            ctx.drawImage(img,0,0);
            var base64Img = canvas.toDataURL('image/png');
            // Clean up
            canvas = null; 
            deferred.resolve(base64Img);
        };
        img.src = element.src;
        return deferred;
    });
    $.when.apply($, promises).then(function() {
        // arguments[0][0] is first result
        // arguments[1][0] is second result and so on
        for (var i = 0; i < arguments.length; i++) {
            var file = new Parse.File("photo.jpg", { base64: arguments[i]}); // this part actually saves the image file to parse
            user.set("image" + i, file); // set this image to the corosponding column on our object 
        }
        var bio = $('#profileDescription').val();
        var city = $('#selectCity').val();
        var men = $('#selectMen').is(':checked'); // returns true or false
        var women = $('#selectWomen').is(':checked'); // returns true or false

        user.set("bio", bio);
        user.set("city", city);
        user.set("menPreference", men);
        user.set("womenPreference", women);

        // save the user object
        user.save(null,{
          success: function(user) { 
                  $('#message').html('Profile Updated!');
                  $('#container').show(); // show the screen again, you should just remove your loading bar now if you used one
          },
          error: function(user, error) {
                  console.log('Failed to create new object, with error code: ' + error.message);
          }
        });
    });
 }


// the below function demonstrates how to retrieve and display images stored on parse       
$('#loadUserData').click(function(){
      event.preventDefault(); // only needed if the clicked element is a link
      var user = Parse.User.current(); 



      var image0 = user.get("image0"); // get the stored image objects
      var image1 = user.get("image1");
      var image2 = user.get("image2");
      // make sure we found images
      if(image0 && image1 && image2){
          var imgElement0 = $('<img>'); // create an image tag
          imgElement0.attr('src', image0.url()); // set the souce or the img tag to the url of the image objct
          $('#image0').html(imgElement0); // display the image

          var imgElement1 = $('<img>');
          imgElement1.attr('src', image1.url());
          $('#image1').html(imgElement1);

          var imgElement2 = $('<img>');
          imgElement2.attr('src', image2.url());
          $('#image2').html(imgElement2);


          var bio = user.get("bio");
          $('#bio').html(bio);

          var city = user.get("city");
          $('#city').html(city);

          var menPreference = user.get("menPreference");
          $('#menPreference').html(menPreference);

          var womenPreference = user.get("womenPreference");
          $('#womenPreference').html(womenPreference);
          $('#message').html('Data retrieved!');
      }
      else{ 
        alert('No data available on the user object. Click "Update Profile" to store the data'); 
      }
  })        

The sudo-html I used for my example:

<div style="margin:auto;width:600;">
<table width="600" border="1" style="margin-left:25px; float:left;">
  <tbody>
    <tr>
      <td>Image 1:</td>
      <td> <img src="http://i.imgur.com/QxD2r0x.png" class="images" /></td>
    </tr>
    <tr>
      <td>Image 2:</td>
      <td> <img src="http://i.imgur.com/sIxiQWH.png" class="images" /></td>
    </tr>
    <tr>
      <td>Image 3:</td>
      <td> <img src="http://i.imgur.com/FgSuSKO.png" class="images" /></td>
    </tr>
    <tr>
      <td>Men:</td>
      <td> <input type="checkbox" id="selectMen" checked /></td>
    </tr>
    <tr>
      <td>Women:</td>
      <td><input type="checkbox" id="selectWomen" checked /></td>
    </tr>
    <tr>
      <td>City: </td>
      <td><input type="text" id="selectCity" value="My city..." /></td>
    </tr>
    <tr>
      <td>Description:</td>
      <td><textarea id="profileDescription">My cool description..."</textarea></td>
    </tr>
    <tr>
      <td colspan="2" style="padding:25px;"><a href="#" id="accountCreation" class="btnLink">Update profile!</a></td>
    </tr>
  </tbody>
</table>


<table width="600" border="1" style="margin-left:25px; float:left;">
  <tbody>
    <tr>
      <td colspan="2" style="padding:25px;"><a href="#" id="loadUserData" class="btnLink">Click Here To Load Stored User Data Below</a></td>
    </tr>
    <tr>
      <td colspan="2" style="padding:25px;"><a href="#" id="resetUser" class="btnLink">Click Here To Reset User</a></td>
    </tr>
    <tr>
      <td>Image 1:</td>
      <td id="image0"></td>
    </tr>
    <tr>
      <td>Image 2:</td>
      <td id="image1"></td>
    </tr>
    <tr>
      <td>Image 3:</td>
      <td id="image2"></td>
    </tr>
    <tr>
      <td>Men: </td>
      <td id="menPreference"></td>
    </tr>
    <tr>
      <td>Women:  </td>
      <td id="womenPreference"></td>
    </tr>
    <tr>
      <td>City:</td>
      <td id="city"> </td>
    </tr>
    <tr>
      <td>Description:</td>
      <td id="bio"></td>
    </tr>
  </tbody>
</table>
<div>
Sign up to request clarification or add additional context in comments.

11 Comments

Thanks for your response. I am working with a cross-platform tool call intel xdk or phonegap, essentially its mainly based on html and javascript, and I can't use php directly. However, there is a work around and i hosted the encodeImgToBase64.php over the cloud and rerefence to it. That seem to have done the trick but I get the following error: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check xhr.spec.whatwg.org. I have included an update section under my initial post
Yeah, I get that too. Its a warning for me though, not an error. It does still work though. Does it work on your platform? The comments inside the ajax function are related to this. Setting async:false throws the warning. Its not the best way to do it. Using promises would be prefered I'm just not that knowledgeable about promises
thank you for your response. the problem is that I also receive the follow error Uncaught TypeError: Cannot read property 'set' of null applicable to the followings user.set("bio", bio); //user.set("city", city); user.set("menPreference", men); user.set("womenPreference", women);
That sounds like you do not have a user loged in, i.e. var user = Parse.User.current(); is returning null I created a single user for the test page I made and wrote a small piece of code near the top to log that user in automatically (you can see that if you "view source" on the demo page), you'll need to log your user in via your login page or whatever you are using before the function will work .
thank you for your suggestion. I did notice that the user was no longer login. If you bear with me, the last dilemna I have is the following: parse-1.3.0.min.js:2 Uncaught TypeError: Cannot read property 'then' of undefined
|
-1

You can't use .value for image tags. To get "src" attribute, use getAttribute() method:

document.getElementById('ID').getAttribute("src")

1 Comment

While this is accurate, it doesn't answer the actual question. This would have been better as a comment

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.