I have an existing django web api with angular frontend, using which i can upload images and display them to the user.Now i want to extend this.On clicking the button "segment"(see image) it should pass the corresponding image to my python script on the backend, which does some processing on the image.
I have my python script in the views.py file of the main app,which is some thing like this:
from django.shortcuts import render
def segment_image(request):
if request.method == 'GET':
form = segment_form()
else:
if form.is_valid():
info = request.POST['info_name']
output = script_function(info)
''' Here i am calling script_function,passing the POST data info to it'''
return render(request, 'your_app/your_template.html', {
'output': output,
})
return render(request, 'your_app/your_template.html', {
'form': form,
})
'''here info is our image in some format'''
def script_function(info):
...
'''here goes my mian logic to process the image.'''
...
return x,y,w,h
I have never worked with images as inputs in angular,i dont know how to route the image using angularjs to my view.Now how can i implement this segmentImage() function in app.js file so that the function would call the corresponding view by passing this image as a POST argument.
Below is my index.html file.
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<!-- Include Angular and several angular libraries -->
<script src="node_modules/angular/angular.min.js"></script>
<script src="node_modules/angular-resource/angular-resource.min.js"></script>
<!-- Include our app -->
<script src="js/app.js"></script>
<!-- Include our own controllers, factories, directives, etc... -->
<script src="js/filesModelDirective.js"></script>
<script src="js/images.rest.js"></script>
<!-- Include Bootstrap CSS -->
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
</head>
<body>
<!-- Main Division -->
<div class="container-fluid">
<div ng-app="imageuploadFrontendApp" ng-controller="MainCtrl">
<!-- Panel for Uploading a new Image -->
<div class="panel panel-default">
<div class="panel-body">
<form class="form" name="form" ng-submit="uploadImage()">
<label for="inputFile">Select Image:</label>
<input id="inputFile" type="file" files-model="newImage.image">
<br />
<button class="btn btn-default" type="submit">
Upload
</button>
<br />
</form>
</div>
</div>
<div ng-if="images.length == 0">
There are no images available yet.
</div>
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-6 col-lg-4" ng-repeat="image in images track by image.pk">
<h3>
Image {{ image.pk }}
<button class="btn btn-warning" ng-click="deleteImage(image)">Delete</button>
<button class="btn btn-primary" ng-click="segmentImage(image)">Segment</button>
</h3>
<a href="{{ image.image }}">
<img class="img-responsive" ng-src="{{ image.image }}">
</a>
</div>
</div>
</div>
</div>
</body>
</html>
Below is my app.js file:
// create a module called imageuploadFrontendApp, which relies on ngResource
var myApp = angular.module('imageuploadFrontendApp', ['ngResource']);
// Configure ngResource to always use trailing slashes (required for django)
myApp.config(function($resourceProvider) {
$resourceProvider.defaults.stripTrailingSlashes = false;
});
// Main Controller
myApp.controller('MainCtrl', function($scope, Images)
{
console.log('In main Control');
$scope.images = Images.query();
$scope.newImage = {};
$scope.uploadImage = function()
{
// call REST API endpoint
Images.save($scope.newImage).$promise.then(
function(response) {
// the response is a valid image, put it at the front of the images array
$scope.images.unshift(response);
},
function(rejection) {
console.log('Failed to upload image');
console.log(rejection);
}
);
};
$scope.deleteImage = function(image)
{
image.$delete(
function(response)
{
// success delete
console.log('Deleted it');
// update $scope.images
$scope.images = Images.query();
},
function(rejection)
{
console.log('Failed to delete image');
console.log(rejection);
}
);
};
});
You can try some thing like this
Define a url for your view function
urls.py
url(r'^image/script_function/$', script_function, name="script_function")
Write the view for the url script_function
views.py
def script_function(info):
...
'''here goes my mian logic to process the image.'''
...
return x,y,w,h
app.js
$scope.segmentImage = function(image){
$http({method:'POST', url:'https://127.0.0.1/image/script_function/', data:{'image': image}}).
then(function successCallback(response) {
console.log('Image Posted successfully')
},function errorCallback(response) {
console.log('Image Post failed')
}
});
};
Pass the image to the sever via post and process your image.
Related
I have an existing views.py file in my django app something like this:
from django.shortcuts import render
def segment_image(request):
if request.method == 'POST':
form = segment_form()
else:
if form.is_valid():
info = request.POST['info_name']
output = script_function(info)
return render(request, 'your_app/your_template.html', {
'output': output,
})
return render(request, 'your_app/your_template.html', {
'form': form,
})
def script_function(info):
'''here goes my main logic'''
x=y=w=h=102
return x,y,w,h
which used to interact with a django template and a django form.But, now i am in the process of shifting everything to a angular frontend app so i replaced the form with a angular $http post.
index.html
<div class="col-xs-12 col-sm-12 col-md-6 col-lg-4" ng-repeat="image in images track by image.pk">
<h3>
Image {{ image.pk }}
<button class="btn btn-warning" ng-click="deleteImage(image)">Delete</button>
<button class="btn btn-primary" ng-click="segmentImage(image)">Segment</button>
</h3>
<a href="{{ image.image }}">
<img class="img-responsive" ng-src="{{ image.image }}">
</a>
</div>
app.js
...
$scope.segmentImage = function(image)
{
$http({method:'POST', url:'127.0.0.1:8000/image/segment_image/', data:{'image': image}})
.then(function successCallback(response)
{
console.log('success')
},function errorCallback(response)
{
console.log('failed')
console.log(response.config)
console.log(response.statusText)
}
)};
...
Now what changes do i need to make to my views.py so that it can recieve the image from angularapp and pass it to my script_function, and render the return values(x,y,w,h) back to index.html
I'm learning laravel 5 about one month, and now i having a problem with javascript.
I add an form click on blade file to delete the post.
But now i don't want to use form, i replace that by javascript.
How can i detect when use touch the delete'button.
#extends ('layouts.master')
#section ('head.title')
Blog
#stop
#section ('body.content')
<div class="container">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
</div>
</div>
<form class="form-show">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<h2> {{ $article->title}} </h2>
<p> {{ $article->content}} </p>
</div>
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
Cập nhật
<button type="submit" class="btn btn-primary">Xoa</button>
</div>
</div>
</div>
</form>
</div>
<script src="jshow.js"></script>
#stop
Add id to button so it is easily locatable in Javascript
<button id="delete-button" type="submit" class="btn btn-primary">Xoa</button>
Next add this javascript
var deleteButton = document.getElementById("delete-button");
deleteButton.onclick = function() { delete(); return false; }
Process the deleting in delete() method
Try this :
<!DOCTYPE html>
<html>
<body>
<button onclick="myFun()">Click me</button>
<p id="demo"></p>
<script>
function myFun() {
console.log('Clicked');
}
</script>
Since HTML forms can't make PUT, PATCH, or DELETE requests, you will need to add a hidden _method field to spoof these HTTP verbs
Also, don't forget to add csrf-token as well which is needed in order to validate a POST request.
First add this meta tag inside your <head>.
<meta name="csrf-token" content="{{ csrf_token() }}">
Then place this code at the top of your JS file.
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
Now, you can make use of data-* attribute to hold the route of that article for AJAX.
<button data-route="{{ route('article.destroy', $article->id) }}" class="btn btn-danger deleteArticle">Delete</button>
In your JS
document.querySelector('.deleteArticle').addEventListener('click', function() {
var route = this.dataset.route;
if (confirm("Are you sure you wish to delete this article?")) {
$.ajax({
method: 'POST',
url: route,
data: {
"_method": 'DELETE',
},
success: function() {
// handle success here
},
error: function() {
// handle error here
},
});
}
});
I created a two panel one for the user's options and the second panel is the transition of the panel. As you can see below I have a group of buttons every-time the user click the buttons the left panel will changed it's content every-time it clicks. But it won't work if I click on the buttons.
I used empty() so it will be empty first the panel-body on my left container after that I will append in the panel-body section
Master page below.
<!DOCTYPE html>
<html>
<head>
<link rel = "stylesheet" href = "{{ URL::asset('css/bootstrap.min.css') }}">
<script type = "text/javascript" src = "{{ URL::asset('js/jquery.js') }}"></script>
<script>
$(document).on("click", "#curriculum", function ()
{
$.get("curriculumOption.blade.php", function (data)
{
$("#rightContainer").empty();
$("#rightContainer").append(data);
alert("This is curriculum");
});
});
$(document).on("click", "#subjects", function ()
{
$.get("subjectsOption.blade.php", function (data)
{
$("#rightContainer").empty();
$("#rightContainer").append(data);
alert("This is subjects");
});
});
</script>
</head>
<body>
#include ('layouts.navigation.user')
<div class="container-fluid">
<div class="row">
<div class="col-lg-3">
<div class = "panel panel-default">
<div class = "panel-body" style = "height: 300px">
<div class = "btn-group" data-toggle = "buttons">
<label class = "btn btn-primary btn-lg">
<input type = "checkbox" id = "curriculum"> Curriculum
</label><br>
<label class = "btn btn-primary btn-lg">
<input type = "checkbox" id = "subjects"> Subjects
</label><br>
</div>
</div>
</div>
</div>
<div class="col-lg-6">
<div class = "panel panel-default">
<div class = "panel-body" id = "rightContainer" style = "height: 300px; overflow-y: scroll;">
//RIGHT CONTAINER
</div>
</div>
</div>
</div>
</div>
OPTIONS:
subjectsOption
curriculumOption
subjectsOption.blade.php
<div class = "btn-group" data-toggle = "buttons">
<label class = "btn btn-primary btn-lg">
<input type = "checkbox" id = "subjectList"> Subject List
</label><br>
<label class = "btn btn-primary btn-lg">
<input type = "checkbox" id = "createSubjects"> Create Subjects
</label><br>
<div>
curriculumOption.blade.php
<div class = "btn-group" data-toggle = "buttons">
<label class = "btn btn-primary btn-lg">
<input type = "checkbox" id = "curriculumList"> Curriculum List
</label><br>
<label class = "btn btn-primary btn-lg">
<input type = "checkbox" id = "createCurriculum"> Create Curriculum
</label><br>
</div>
I don't understand why you out checkbox in label. I have just remove the checkbox and add id to labels.
Add insert php file data using html()function.
<!DOCTYPE html>
<html>
<head>
<link rel = "stylesheet" href = "{{ URL::asset('css/bootstrap.min.css') }}">
<script type = "text/javascript" src = "{{ URL::asset('js/jquery.js') }}"></script>
<script>
$(document).on("click", "#curriculum", function ()
{
$.get("curriculumOption.blade.php", function (data)
{
//$("#rightContainer").empty();
$("#rightContainer").html(data);
alert("This is curriculum");
});
});
$(document).on("click", "#subjects", function ()
{
$.get("subjectsOption.blade.php", function (data)
{
//$("#rightContainer").empty();
$("#rightContainer").html(data);
alert("This is subjects");
});
});
</script>
</head>
<body>
#include ('layouts.navigation.user')
<div class="container-fluid">
<div class="row">
<div class="col-lg-3">
<div class = "panel panel-default">
<div class = "panel-body" style = "height: 300px">
<div class = "btn-group" data-toggle = "buttons">
<label class = "btn btn-primary btn-lg" id = "curriculum">
Curriculum
</label><br>
<label class = "btn btn-primary btn-lg" id = "subjects">
Subjects
</label><br>
</div>
</div>
</div>
</div>
<div class="col-lg-6">
<div class = "panel panel-default">
<div class = "panel-body" id = "rightContainer" style = "height: 300px; overflow-y: scroll;">
//RIGHT CONTAINER
</div>
</div>
</div>
</div>
</div>
Laravel Blade Template, or PHP file inside the /resources/views inside Laravel framework is not accessible using URL directly, to be precise, everything under /resources folder and even all other folders except /public, are not accessible. Only public folder can be accessed directly by using URL in laravel framework. You must notice that the view inside resources folder can only be returned after come from route -> controller -> view to be simple.
Thus, this part of your code
$(document).on("click", "#curriculum", function ()
{
$.get("curriculumOption.blade.php", function (data)
{
$("#rightContainer").empty();
$("#rightContainer").append(data);
alert("This is curriculum");
});
});
$(document).on("click", "#subjects", function ()
{
$.get("subjectsOption.blade.php", function (data)
{
$("#rightContainer").empty();
$("#rightContainer").append(data);
alert("This is subjects");
});
});
is trying to access your server in certain URL. lets take example your domain is test.laravel.dev and you are in root of your domain (in your browser you can see http://test.laravel.dev), and you run these script there. It means that you are trying to do AJAX request to url http://test.laravel.dev/curriculumOption.blade.php and http://test.laravel.dev/subjectOption.blade.php. What will happens? this will try to find route in your routes.php file, looking for "/curriculumOption.blade.php" or "/subjectOption.blade.php" which i am sure it's not exists there. what you can do is, if you still need the blade template to be processed before returning as AJAX response, you can make it like this:
routes.php
Route::get("/curriculumOption","CurriculumOptionController#show");
CurriculumOptionController.php
public function show()
{
//do your things here
return view("curriculumOption");
}
with the curriculumOption.blade.php is under /resources/views folder, and change your ajax request to:
$(document).on("click", "#curriculum", function ()
{
$.get("/curriculumOption", function (data)
{
$("#rightContainer").empty();
$("#rightContainer").append(data);
alert("This is curriculum");
});
});
This will work, please try and ask if have any other problem.
Explanation #1
Due to some security reason and also as a feature for laravel, most of the folders except public cannot be accessed without PHP preprocessor. When you are making a request in browser, the HTTP request is being sent to your browser to the server. in this case, if you make get request, you dont pass any other additional form parameters to server. Server read the request URL from your browser and then there are some server configuration in how are they going to pass the parameter to PHP preprocessor. These configuration is set in .htaccess file for apache HTTP server, nginx configuration for NGINX, and web.config for IIS server. You can notice that the .htaccess file is included in your /public folder of laravel project and the /public folder is the default for your domain, lets say your domain is test.laravel.dev, then test.laravel.dev is equal to /public and test.laravel.dev/index.php is refering to /public/index.php file. The rest that can be put in /public usually are css, javascript, and image files. Templates, Controller, Routes, etc are not accessible from URL. They are being managed by the framework. /resource folder is not accessible for security reason also. The only way is to access it from route or controller. If you dont define what to do with a certain URI, laravel framework will not give a proper response which is most likely erorr. Your /management/curriculumOption.blade.php can't be accessed simply because you dont have a route with
Route::get("/management/curriculumOption.blade.php"/, .....)
even though i dont think you can put .blade.php in the parameters also, but worth to try. There are only 2 options(need citation) to access certain URL to be responded in Laravel:
Define it in routes.php
put it in public folder
I am building a very basic angular app to learn. My app basically loads a list of users and prints them all out on the home page with a checkbox next to each name and also displays the number of present users.
The list of users appears to work - I have 11 users and 11 checkboxes show up. HOWEVER, the actual text doesn't show up. The users.length variable also shows up as empty too.
Here is my core.js file:
var userApp = angular.module('userApp', []);
userApp.controller("mainController", mainController);
function mainController($scope, $http) {
$scope.formData = [];
// when landing on the page, get all users and show them
$http.get('/api/users')
.success(function(data) {
$scope.users = data;
console.log(data);
console.log(data.length);
})
.error(function(data) {
console.log('Error: ' + data);
});
// when submitting the add form, send the text to the node API
$scope.createUser = function() {
$http.post('/api/users', $scope.formData)
.success(function(data) {
$scope.formData = {} //clear the form so our user is ready to enter another user
$scope.users = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
}
And here is my index.html file:
<html ng-app="userApp">
<head>
<!-- META -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"><!-- Optimize mobile viewport -->
<title>Node/Angular Todo App</title>
<!-- SCROLLS -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"><!-- load bootstrap -->
<style>
html { overflow-y:scroll; }
body { padding-top:50px; }
</style>
<!-- SPELLS -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script><!-- load jquery -->
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script><!-- load angular -->
<script src="core.js"></script>
</head>
<body ng-controller="mainController">
<div class="container">
<div class="jumbotron text-center">
<h1>Users Count: <span class="label label-info"> {{ users.length }}</span></h1>
</div>
<div id="user-list" class="row">
<div class="col-sm-4 col-sm-offset-4">
<!-- loop over users -->
<div class="checkbox" ng-repeat="user in users">
<label>
<input type="checkbox">{{ user.first_name }}
</label>
</div>
</div>
</div>
<!-- create users -->
<div id="user-form" class="row">
<div class="col-sm-8 col-sm-offset-2 text-center">
<form>
<div class="form-group">
<!-- BIND THIS VALUE TO formData.text IN ANGULAR -->
<input type="text" class="form-control input-lg text-center" placeholder="I want to buy a puppy that will love me forever" ng-model="formData.text">
</div>
<!-- createUser() WILL CREATE NEW USERS -->
<button type="submit" class="btn btn-primary btn-lg" ng-click="createUser()">Add</button>
</form>
</div>
</div>
</div>
</body>
</html>
Sample user record:
{
"id": 1,
"first_name": "Bruce",
"last_name": "Lee",
"email": "blee#email.com",
"password": "blee",
"created_at": "2016-01-08T21:49:18.337Z",
"updated_at": "2016-01-08T21:49:18.337Z"
},
The data also properly console.log()'s.
Can someone help?
Thanks in advance!
If you want to take over user data to Angular, you should fix {{ first_name }} to {{ user.first_name }} in your html.
It means that each label get name from not globally declared but user.
Moreover you should better register controller in your js code.
in core.js
userApp.controller("mainController", mainController);
The $http service for angular should return a response object and not the raw data. According to the docs this is what is in this object:
The response object has these properties:
data – {string|Object} – The response body transformed with the transform functions.
status – {number} – HTTP status code of the response.
headers – {function([headerName])} – Header getter function.
config – {Object} – The configuration object that was used to generate the request.
statusText – {string} – HTTP status text of the response.
```
Try assigning data.data to the $scope.users variable like so:
$http.get('/api/users')
.success(function(data) {
$scope.users = data.data; // <-------- here!!! (consider calling it response so you can use 'response.data'
console.log(data);
console.log(data.length);
})
.error(function(data) {
console.log('Error: ' + data);
});
Quick edit: it also seems like you are using the old way of doing things (.success and .error). The service returns a promise and you should be consuming it with .then.
Example
$http
.get('/api/users')
.then(function(response) {
$scope.users = response.data;
}, function(error) {
console.log('Error: ' + error);
});
This is the error im having from Google Devt Tools. Anyone knows the problem? I tried to change in many times including the file structure and the stateProvider (no controllers for that) in app.js file but it does not seem to be the issue. (script is included in app.js with correct file name and directory)
In addition, my logout and submitPost buttons arent working as well.
newpost.html
<div class="modal slide-in-up" ng-controller="NavCtrl">
<!-- Modal header bar -->
<header class="bar bar-header bar-secondary">
<button class="button button-clear button-primary" ng-click="close()">Cancel</button>
<h1 class="title">New Shout</h1>
<button class="button button-positive" ng-click="submitPost()">Done</button>
</header>
<!-- Modal content area -->
<ion-content class="padding has-header">
<form class ng-submit="submitPost()" ng-show="signedIn()">
<div class="form-group">
<input type="text" class="form-control" placeholder="Title" ng-model="post.title">
</div>
<div class="form-group">
<input type="text" class="form-control" placeholder="Link" ng-model="post.url">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</ion-content>
</div>
controller.js file
app.controller('NavCtrl', function ($scope, $firebase, $location, Post, Auth, $ionicModal) {
$scope.post = {url: 'http://', title: ''};
// Create and load the Modal
$ionicModal.fromTemplateUrl('newpost.html', function(modal) {
$scope.taskModal = modal;
}, {
scope: $scope,
animation: 'slide-in-up'
});
// Open our new task modal
$scope.submitPost = function () {
Post.create($scope.post).then(function (postId) {
$scope.post = {url: 'http://', title: ''};
$location.path('/posts/' + postId);
$scope.taskModal.show();
});
};
$scope.close = function() {
$scope.taskModal.hide();
};
$scope.logout = function () {
Auth.logout();
};
});
List of items page, post.html
<ion-header-bar class="bar-positive" ng-controller="NavCtrl">
<button class="button button-clear" ng-click="submitPost()">New</button>
<h1 class="title"><b><a class="navbar-brand" href="#/posts">MyApp</a></b></h1>
<button class="button button-clear" ng-click="logout()">Logout</button>
</ion-header-bar>
Change <base href="/"> to <base href="./"> from index.html
404 literally means that file was not found. It's simple as that. Check if the URL is right, and there are no rediretions being done(use fiddler). Perhaps the protocol should be https:// istead of http://? Perhaps you need "www" in url?
Click the url given in Chrome and see if the file exists.
Not sure if anyone is interested, but Experienced a similar problem when trying to upload to firebase storage here is how i resolved it.
The Error screenshot where upload fails with 503 and then 400 after 75% progress
The code segment I use for Upload is
//Event: data.Event,
// Date: data.Date,
// Time: data.Time
var data = getData();
data.filename=uploadfile.name;
var metadata = {
customMetadata: {
data
}
}
var storageRef = firebase.storage().ref().child("features");
console.log("Filenames to upload :" + uploadfile.name);
var fileRef = storageRef.child(uploadfile.name);
var uploadTask = fileRef.put(uploadfile,metadata);
The Problem was with custom meta data, once I changed it to like this,
var metadata = {
customMetadata: {
Event: data.Event,
Date: data.Date,
Time: data.Time
}
}
the upload started working. So, if there is an error in setting custom meta data, firebase errors out and possible does not provide that as a reason.
Screenshot of working here
successful upload once the custom meta data is corrected