Reading and writing to a server-side file in AngularJS - javascript

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(',')
})}

Related

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.

Retrieve part of json file from an external website (sparkfun)

This question might be quite specific to sparkfun, but I still wish to make it as a general question due to my limited experience in javascript.
I have been using the follow html and javascript (d3.js) file to load json data from sparkfun data server:
index.html
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var data_sensor;
var url = "https://data.sparkfun.com/output/w5nEnw974mswgrx0ALOE.json"
d3.json(url, function (error,json) {
if (error) throw error;
data_sensor=json;
console.log(data_sensor)
})
</script>
</body>
After running the script, i will end up with all data array stored in variable data_sensor for post-analyse.
What i wish to do now is to create a dash board that downloads and stores only the latest value. i understand that i could just use the first value in the data_sensor to do so (i.e., data_sensor[0]) but such method becomes quite inefficient with the growth of data.
Thanks!
When I've wanted to load JSON from somewhere I've always used jQuery:
Import jQuery like this:
<script src="jquery-3.2.1.min.js"></script>
Then you can do something like this to get your JSON file:
var data_sensor;
var url = "https://data.sparkfun.com/output/w5nEnw974mswgrx0ALOE.json"
$.getJSON(url, function(data) {
data_sensor = data;
console.log(data_sensor)
});
Hope that helps!
Not an expert here, but their docs state tat you can use paging to get the first 250kb of data:
var url = "https://data.sparkfun.com/output/w5nEnw974mswgrx0ALOE.json?page=1";
You can get your first object/set of data, and I'm afraid there's no general way to take only part of any API response - request is request, it could send you every possible data depending on architecture, from "OK" string to 200MB of data. Carefully reading docs is your best bet.

Angular Schema Form Load Data from JSON

I'm an hardware engineer trying to create an in-house software tool. I thought that I would be able to do so quite easily, but there are a few too many unknowns for me to progress.
I'm trying to create an in-house software solution for managing orders. I have defined a JSON Schema that is valid.
I want to set up a webpage where I can create a new order by filling out a web form. The data should then be stored as a JSON text file. I also want to be able to load a JSON text file, pre-populate the form with the current values, make some changes, and then save the changes.
I've done similar things in php and mysql, but I want to use JSON files to be able to make changes to the software tool without having to fiddle around with a database structure. I also see it as a good learning opportunity.
I'm trying to use auto generated forms (schemaform.io), and I've gotten the following code to work:
<!DOCTYPE html>
<html >
<head>
</head>
<body ng-app="test" ng-controller="FormController">
<form name="ngform"
sf-schema="schema"
sf-form="form"
sf-model="model"></form>
<script type="text/javascript" src="../bower_components/angular/angular.js"></script>
<script type="text/javascript" src="../bower_components/angular-sanitize/angular-sanitize.min.js"></script>
<script type="text/javascript" src="../bower_components/tv4/tv4.js"></script>
<script type="text/javascript" src="../bower_components/objectpath/lib/ObjectPath.js"></script>
<script type="text/javascript" src="../bower_components/angular-schema-form/dist/schema-form.min.js"></script>
<script type="text/javascript" src="../bower_components/angular-schema-form/dist/bootstrap-decorator.min.js"></script>
<script type="text/javascript" src="../bower_components/jquery/dist/jquery.js"></script>
</script>
<script>
/*
$.getJSON("data/order.json", function(orderTemplateJson) {
console.log(orderTemplateJson); // this will show the info it in firebug console
$scope.$broadcast('schemaFormRedraw')
});
*/
var app = angular.module('test',['schemaForm']);
app.controller('FormController', function($scope,$http){
$scope.schema = {
// A long long string of text goes here
};
$scope.form = [
"*",
{
type: "submit",
title: "Save"
}
];
$scope.model = {};
})
</script>
</body>
</html>
I now want to load the JSON schema from a file. I tried to move the code into the callback of a getJSON call, but I got the following error message:
Uncaught Error: [$injector:modulerr] Failed to instantiate module test due to:
Error: [$injector:nomod] Module 'test' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
$.getJSON("data/order.json", function(orderTemplateJson) {
console.log(orderTemplateJson);
//Moved all the angular module code to here
});
I've tried various things, but the problem is likely that I don't really know what I'm doing.. Any help would be greatly appreciated.
Also, does anyone have any pointers on how I can pre-load the form with data from a JSON-file that contains data (and fits the schema)?
Thank you..
/ Martin
While using angular it's good to do things the angular way. So first thing is that you should use angular's $http to load file instead of jQuery's $.getJSON. So in your controller you can do:
app.controller('FormController', function($scope,$http){
$http.get("data/order.json").then(
function success(response) {
// please note that as this is asynchronous,
// the $scope.schema will be available after response
// has been received but this should be ok
$scope.schema = angular.fromJson(response.data);
},
function error(response) { /* handle error */ });
// do other stuff
});
then angular $http API reference will be helpful
there are other things to consider using angular however it's worth to invest some time to familiarize with the angular way and benefit from it relatively quickly.
Even more helpful would be to use $resource instead of $http as it is dedicated to deal with json (and REST actually).

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

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.

Can $http.put write data to JSON file

I apologize for the newbie question but I am getting conflicting answers to this while searching on the net.
I have created an AngularJS app to read from a JSON file using $http.get and display the data as a form with each form element binded with ng-model. Ideally I would like the user to be able to edit the desired field and click save, then have that data updated in the JSON file. I have been told that to do this you will need a 3rd party server like NodeJS, but I am seeing other examples that show it being done in videos. Can someone tell me if this is possible without the 3rd party server and if so what is the best practice for doing this.
Thank you
$http GET (for resource located on client) will not work with the Chrome browser and will give a CORS error (unless you disable Chrome web security by opening Chrome using run .../chrome.exe" --allow-file-access-from-files -disable-web-security). Firefox gives an error saying the JSON in not well formed even though it is. Browsers don't seem to like it.
HTML5 LocalStorage is your best bet for client storage where you wish to perform CRUD operations and have the data survive past page refresh. A good example of this is the [TodoMVC example]
(https://github.com/tastejs/todomvc/tree/gh-pages/architecture-examples/angularjs)
A very simple example that saves a json file to localstorage and reads the contents of localstorage is shown. The Service contains a getter and a setter method to interact with localstorage.
INDEX.HTML
<body ng-app = "app">
<div ng-controller="MainCtrl">
<form>
<input placeholder="Enter Name.." ng-model="newContact"/>
<button type="submit" class="btn btn-primary btn-lg"
ng-click="addContact(newContact)">Add
</button>
</form>
<div ng-repeat="contact in contacts track by $index">
{{contact.name}}
</div>
</div>
APP.JS
angular.module('app', ['app.services'] )
.controller('MainCtrl', function ($scope, html5LocalStorage) {
//create variable to hold the JSON
var contacts = $scope.contacts = html5LocalStorage.get();
$scope.addContact = function(contact) {
$scope.contacts.push( {"name":contact} ); //Add new value
html5LocalStorage.put($scope.contacts); //save contacts to local storeage
}
});
SERVICES.JS
angular.module('app.services', [] )
.factory('html5LocalStorage', function () {
var STORAGE_ID = 'localStorageWith_nG_KEY'; //the Local storage Key
return {
//Get the localstorage value
get: function ()
{
return JSON.parse(localStorage.getItem(STORAGE_ID) || '[]');
},
//Set the localstorage Value
put: function (values)
{
localStorage.setItem(STORAGE_ID, JSON.stringify(values));
}
};
});
Otherwise you could use Node and Express and store the JSON file on the server. Use file system module 'fs-extra' to interact with the json file.
You would have to create RESTful API routes for the client to interact with the server using $http and perform CRUD operations.
/put
/get
/delete
/post
I would be interested to see these videos of this being done without the server writing to the file. You cant just "post the .json file" and have it replace the old one, unless you configure your server (apache, nginx, tomcat, node) to do so.

Categories