How can I use Angular $http.post() to update a JSON file? - javascript

For now, all I'm trying to do is read in a simple JSON file, allow the user to edit the contents, and then save it back to the same file. I've read several answers like this, but I'm not dealing with form data or trying to cut out jquery and my understanding (probably the issue) is that it shouldn't be that complicated.
Working off of this answer, here's what I've got:
<div ng-controller="myCtrl as items">
<table>
<tr ng-repeat="item in items.testData">
<td><strong>Name:</strong></td>
<td><input ng-model="item"></td>
</tr>
</table>
<button ng-click="items.update()">Submit</button>
<p>{{items.msg}}</p>
</div>
In the app.js:
(function() {
var app = angular.module("myApp", []);
app.controller("myCtrl", ["$http", function($http) {
var list = this;
this.testData = [];
$http.get("test.json").success(function(data) {
list.testData = data);
});
this.msg = "";
this.update = function() {
$http.post("test.json", list.testData);
this.msg = "saved:" + JSON.stringify(list.testData);
};
}]);
})();
And finally the JSON, just so you see what I see:
[
"first item",
"second item",
"3rd item",
"And fourth"
]
I'm only working locally right now, so there shouldn't be any issue with my server failing to understand the output (as discussed here). I'm just going JSON to JSON.
Now, my observations-
(most importantly) test.json never changes when I update(), maybe because
testData doesn't seem to actually change, according to the output in msg. Is something wrong with my ng-model? It works in the above example.
There's no error for trying to post to test.json, but if I instead set the destination as test-new.json, I get Access to restricted URI denied. Can I not actually write to a local file at all?
Hopefully, I'm right that this deserved its own question; nothing else I looked at seemed to answer just the basic problems I'm having. Any help greatly appreciated.

Related

Rendering HTML elements from a JSON object get. How to render HTML?

Feels good to finally submit some of my own questions here in the pursuit of knowledge. I was wondering if anyone could help me with the following problem. I have a jQuery GET where a JSON object gets pulled via an API.
My code:
var div = document.getElementById('myData');
jQuery(document).ready(function() {
const Url = 'https://boards-api.greenhouse.io/v1/boards/sunrock/jobs/5104060003';
jQuery('.btn').click(function() {
jQuery.ajax({
url: Url,
type: 'GET',
success: function(result) {
console.log(result);
x = result.title
var jobTitle = x;
document.getElementById('jobTitle').innerHTML = jobTitle;
y = result.content
var jobDescription = y;
document.getElementById('jobDescription').innerHTML = jobDescription;
},
error: function(error) {
console.log(`Error ${error}`)
},
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button class='btn'>
Clicke here for the GET request
</button>
<div id='jobTitle'>Job Title here</div>
<div id='jobDescription'>Job Description here</div>
I want some of this information to display in HTML. But whenever i apply a variable with the information to a div using innerHTML, i get the following:
<p><strong>Your role</strong></p> <p>
As you can see the HTML elements are typed out fully, which is weird. Does anyone know how to remedy this?
I have a jsFiddle with my code here: https://jsfiddle.net/whimsicalcodingman/38a45udt/159/
As #GrafiCode pointed out, the issue isn't in your code, when you access the content property. The issue is in the information you are receiving for the content property.
The property content returns this:
"content": "<p><strong>Your role</strong></p>\n<p>The Project Finance...
Which is:
"content": "<p><strong>Your role</strong></p>\n<p>The Project Finance...
Therefore, I see two options for you, you can either fix this in the backend or fix this in the frontend.
If you want to fix this in the frontend, then you might be interested to use an HTML Sanitizer.
For example, you could Mozilla's HTML Sanitizer API
If you want to fix this in the backend, you can either fix the text manually or you can try to find a library.
For example, if your backend is NodeJS, then you can use this package library sanitize-html

Adding Angular to an existing CodeIgniter project

I am using CodeIgniter on a daily basis as a frontend and backend development framework and I'am using dynamic frontend stuff like reacting forms and Ajax very rarely. But I need to say: I love it because it's most user-friendly and that's the key of good frontend development.
With forms for example I'm going with to good old way by posting to e new file, validating and pushing it to the database or wherever.
I'll like the way of validating it and giving feedback while the user is typing and this is where I came to angular.
First and foremost I like Angular for reacting forms. For the beginning I'll use it with forms only.
How can I combine CodeIgniter's folder structure with angular's folder structure so that I can use first and foremost CI but angular for the form handling.
Angular usually serves the content from AJAX calls, so you should use CodeIgniter as the webservice API framework.
Let's think you're going to implement a simple list:
First, create your Angular project using sample data (by hardcoding values, for example). When you have your product list working.
HTML
var app = angular.module('myApp', []);
app.controller('MainCtrl', function($scope) {
$scope.items = [
"One",
"Two",
"Three",
"Four"
];
});
angular.bootstrap(document, ['myApp']);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="MainCtrl">
<ul>
<li ng-repeat="item in items">
{{item}}
</li>
</ul>
</div>
For now, elements are hardcoded. But we need this elements to be dynamic, with CodeIgniter served data.
For that, create a folder named 'api' at the 'www' folder of your server. Then upload all the CodeIgniter source files. If you have done it correctly, you should see the 'Welcome' controller when you access 'http://yourdomain.com/api'.
For this, I recommend to use this CodeIgniter plugin that allows you to easily create a Webservice API Rest. The main objective is to serve a json object when the Angular asks for data. Then Angular will do the rest.
A brief example:
<?php
header("Content-type: application/json");
class List extends CI_Controller
{
function __construct()
{
// Here you can load stuff like models or libraries if you need
$this->load->model("list_model"); // For example
}
/**
* This method receives a parameter so it can
* filter what list wants the client to get
*/
public function list1($list_number)
{
$list = $this->list_model->getList($list_number);
// If list not exists
if ( empty($list) ) {
$this->output->set_status_header(404);
echo json_encode(
"success" => false,
);
return;
} else { // If has returned a list
// CodeIgniter returns an HTTP 200 OK by default
echo json_encode(
"success" => true,
"list" => $list,
);
return;
}
}
}
Now we can take the info by AJAX. The same code above but changed to get the remote data:
var app = angular.module('myApp', []);
app.controller('MainCtrl', ['$scope', '$http', function($scope, $http) {
// Replace link bellow by the API url
// For this example it would be:
// http://yourdomain.com/api/list/list1/1
$http.get("https://codepen.io/anon/pen/VExQdK.js").
success(function(res) {
console.log(res);
if ( res.success == true ) {
$scope.items = res.items;
} else {
$scope.items = [];
}
});
}]);
angular.bootstrap(document, ['myApp']);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="MainCtrl">
<ul>
<li ng-repeat="item in items">
{{item.name}}
</li>
</ul>
</div>
This way you can get a completely functional CodeIgniter API working with Angular. I like to organize methods in different controllers so code is structured to be "readable".
To modify or delete data on the server, you can use $http.post and send parameters to tell CodeIgniter which kind of operation has to do. Remember to use session data to protect the ajax calls of modifying/deleting information (for example if a user tries to update other user's info).
This is not a definitive way, but it's mine. I hope it helped you.

ng-repeat not displaying data from http request. getting commented when inspecting [duplicate]

This question already has answers here:
How to enable CORS in AngularJs
(10 answers)
How does the 'Access-Control-Allow-Origin' header work?
(19 answers)
Why does my JavaScript code receive a "No 'Access-Control-Allow-Origin' header is present on the requested resource" error, while Postman does not?
(13 answers)
Closed 4 years ago.
My
homeController.js
var app = angular.module('myApp');
app.controller('HomeController',
function($scope, $http, $rootScope, $stateParams, $state, LoginService) {
$scope.user = $rootScope.userName;
console.log("Starting http request");
$http.get("http://127.0.0.1:5000/trying").success(function (response) {
$scope.myData = response.users;
console.log(response);
});
console.log("ending http request");
});
<div class="col-md-12" style="width:500px;">
<div align="right"><a ui-sref="login">Logout</a></div>
<h4>Welcome {{user}}! </h4>
<p><strong>This is Home Page</strong></p>
<ul>
<li ng-repeat="x in myData">
Data are : {{ x.fname + ', ' + x.coordinates }}
</li>
</ul>
</div>
Console
Response object
The home.html is getting rendered from index.html. It is doing it fine as can be the user with which am logging in is displaying. However the ng-repeat is not working fine. When inspecting its showing that its getting commented out. What am i doing wrong?
I would make sure that $scope.myData exists outsideof the http.get function. Define it as an array or dictionary/obj right above the http.get function, and under $scope.user... that way the view knows what to expect.
Is myData an array or a dictionary? make sure you are using the correct looping syntax (x in myData vs x of myData). Can also do (dataKey, dataValue) in myData
I usu sally add an ng-if="!isLoading" to the ng-repeat if the contents are dependent on an http call. Initially I set in the this.$onInit function (which gets called automatically once the page is ready to be initialized) then in the response set it to isLoading = false.
`
this.$onInit = function(){
$scope.isLoading = true;
// rest of the stuff like http.get...
$http.get("http://127.0.0.1:5000/trying").success(function (response)
$scope.myData = response.users;
$scope.isLoading = false;
console.log(response);
});
};
`
Let me know if that helps the behavior. of your view, it could also be that the view isn't updating for some other reason.
PRO TIP: When you define your $scope.myData initially, IT MUST be the same type of variable that you are returning if you want ng-repeat to behave correctly.
None of this, "declared as [] but then fills in as a {} later on with an api call".
This is one of those things that can ghost you hard since vanilla javascript is pretty hands off with variable type swapping. The view will just ignore the code smell and not do anything... which can be pretty darn frustrating if you don't know what to look for. This is why some developers have gone off to typescript and other flavors of javascript that are a bit more cemented in what they allow you to do with variable... but that is another post completely.

Tumblr API displaying post text from JSON

I have created a tumblr blog with two basic text posts to prove a concept...failing at the minute.
Using this example: http://jsfiddle.net/keckclip/9LNDX/5/ and by replacing the api_key and url only I can return the title etc but nothing within the post section of the json. I understand it's anarray but this is the code I have but it doesn't display anything from the posts.
$(document).ready(function () {
var API_KEY = "api key goes here";
var tumblrAPI = "http://api.tumblr.com/v2/blog/blogurlgoesintohere/posts/text?api_key=" + API_KEY + "&callback=?";
$.getJSON(tumblrAPI).done(function (data) {
$('#blog_title').append(data.response.blog.name);
$.each(data.response.posts, function (i, item) {
$("<div>").addClass("post").html(item.text).appendTo("#posts");
});
});
});
Seen quite a few examples but none explicitly explaining the best way to display post data.
My html includes:
<div id="blog_title" class="col-md-12"></div>
<div id="blog_post" class="col-md-12"></div>
I know, as always, it is likely something obvious but I would appreciate some assistance.
I know there are similar questions out there but I think mine is a different problem, perhaps nobody is as naive as me.
Edit -> the json is correct...

Reading and writing to a server-side file in AngularJS

I'm attempting to create a simple guestbook with AngularJS, and read and write the names to a simple file. Trouble is, I can't seem to get my code to even read from the file.
This is my directory structure:
This is index.html:
<!DOCTYPE html>
<html ng-app>
<head>
<meta charset="ISO-8859-1">
<title>GuestBook</title>
<script src="http://code.angularjs.org/angular-1.0.0rc3.min.js"></script>
<script type="text/javascript" src="javascript/user.js"></script>
</head>
<body>
<h1>Welcome!</h1>
<div ng-controller="UserCtrl">
<ul class="unstyled">
<li ng-repeat="user in users">
{{user}}
</li>
</ul>
</div>
</body>
</html>
This is user.js (Based off this question/answer):
function UserCtrl($scope) {
$scope.users = $(function() {
$.get('data/users', function(data) {
var array = data.split(',');
console.log(array);
});
});
}
And this is my users file:
John,Jacob,James
I'm expecting this outcome:
Welcome!
John
Jacob
James
But instead, all I get is:
Welcome!
So my question is, how can I populate $scope.users with the names in the users file?
I know I've got my AngularJS set up correctly because I was able to get the desired result when I hard-coded it:
$scope.users =[John,Jacob,James];
I've also spent a lot of time googling and searching Stack Overflow for how to read and write to a file with JavaScript and/or AngularJS, but:
No one seems to be trying to do exactly what I'm trying to do;The instructions are either confusing or not really applicable to what I'm trying to do.
I'm also not sure where to begin to write code that will persist names to the users file -- but I'll be happy if I can just read the file for now, and ask how to write to it later in a separate question. (But extra gratitude if you do also show me how to write to it.)
Try injecting angular's $http service into your controller first of all. And make sure you add a '/' before your 'data/users' path. (/data/users)
function UserCtrl($scope, $http) {
$scope.users = [];
$http.get('/data/users')
.success(function(data, status, headers, config) {
if (data && status === 200) {
$scope.users = data.split(',');
console.log($scope.users);
}
});
});
}
You can check your console to see what kind of data is being returned. (Network tab)
edit: just realized the $(function ... part didn't make sense.
The problem with your code is in this stub -
$scope.users = $(function() {
$.get('data/users', function(data) {
var array = data.split(',');
console.log(array);
});
});
Here $scope.users is not the array variable. Instead, it is whatever $() returns.
Your anonymous function is passed only as a parameter to $ function.
Rewrite your controller this way -
function UserCtrl($scope, $http) {
$scope.users = [] // Initialize with an empty array
$http.get('data/users').success(function(data, status, headers, config) {
// When the request is successful, add value to $scope.users
$scope.users = data.split(',')
})
}
And now, since you have
<li ng-repeat="user in users">
{{user}}
</li>
in your view, angular will set up a watch on $scope.users variable.
If the value of $scope.users changes anytime in the future, angular will automatically
update the view.
EDIT -
Along with the above edit, you need to make sure all the files are being served via a web server on the same host:port. Browsers limit AJAX access to another domain:port. Here is a quick way to do start a http server -
Go to the project directory using terminal and type in
python -m SimpleHTTPServer for python
or
ruby -run -e httpd -- -p 8000 . for ruby.
Both will start a basic HTTP server at port 8000, serving content from that particular directory. Having done this, your index.html will be at http://localhost:8000/index.html and your data file should be accessibe as http://localhost:8000/data/user.js (your javascript can still use /data/user.js).
It turns out I can't do what I'm trying to do the way I'm trying to do it. JavaScript by itself can't read files on the Server-Side, only on the Client-Side. To read and persist data, JavaScript has to make calls to a "Back-end" or server, written in something like Java, which isn't just a Browser scripting language.
you entered 'users' instead of 'users.txt' as filename.
This works just fine to me:
function UserCtrl($scope, $http) {
$scope.users = []
$http.get('data/users.txt').success(function(data, status, headers, config) {
$scope.users = data.split(',')
})}

Categories