Parse an HTML document with AngularJS - javascript

I'm attempting to write a simple drop-in hockey application in AngularJS. It will aggregate schedule data from local rinks and show it on a single page per metro area. However, some of the sites I'm aggregating from don't appear to support JSON, so I'm tasked with scraping HTML and then parsing it for time/date info. My question is: is there an idiomatic way to parse and display scraped HTML data in Angular?
I bootstrapped the project with Yeoman + Bower. The controller for Denver-area drop-in looks like this:
angular.module('dropinApp')
.controller('DenverCtrl', function ($scope, $http, $sanitize) {
// Pull data from a pre-scraped html frame to get around CORS issues.
/* http://denveruniv-web.ungerboeck.com/coe/coe_p1_all.aspx?oc=01&cc=ICEDI30#mainContent */
$http.get('/dropin_data/du-schedule.html').
success(function(data, status, headers, config) {
$scope.duHtmlData = data;
$scope.duStatus = status;
}).
error(function(data, status, headers, config) {
$scope.duData = data;
$scope.duStatus = status;
});
// Yeoman/Bower stuff
$scope.awesomeThings = [
'HTML5 Boilerplate',
'AngularJS',
'Karma'
];
});
I've tried several different ways to inject this into my Denver partial. This is the most recent:
<!-- denver.html -->
<p>Denver Drop-In.</p>
<p ng-bind-html="duHtmlData">{{ duHtmlData }}</p>
<p>status is {{ duStatus }}</p>
This fails with:
Error: [$sanitize:badparse] The sanitizer was unable to parse the following block of html: <!-- Body Listing ---------------->...
I've also tried doing the parsing inside my controller: $scope.duParsedData = $sanitize(duHtmlData) which generates roughly the same error. The HTML file is simply a curl dump from DU's website.
Syntax issues aside, is this approach correct? Is there a more idiomatic way to scrape/parse third-party HTML in Angular?

You can use $sce service. See this fiddle.
$scope.t = $sce.trustAsHtml(html);
I added some of the page's Html. Comment did not raise an issue.
<!-- Body Listing ---------------->

Related

Presenting answers dynamically from a large API using angular js (fetch)

My goal is to create a function to shows hearthstone cards from the game. My API is working and I am fetching the data from the API, no problem here. The problem I run into is to show the result in my HTML page.
I've tried different object calls within the angular tag {{ }}, but the closest I've gotten is giving me the result of [[Object Object]].
Right now I am working on getting the API and HTML page to work correctly, so everything is in sync, so I am not looking for a full solution on a search engine through the data, just so that it syncs with my HTML page and shows the data I am calling (specific hardcoded data location).
This is all the code inside the controller:
var produkterControllers = angular.module('produkterControllers', []);
produkterControllers.controller('minApiFunktionController', function myController($scope, $http, $q) {
var fetchPromise = fetch("https://omgvamp-hearthstone-v1.p.rapidapi.com/cards", {
"method": "GET",
"headers": {
"x-rapidapi-host": "omgvamp-hearthstone-v1.p.rapidapi.com",
"x-rapidapi-key": "8ad5a16c67mshed80ba15c31ab54p141ec5jsnfbff6480fd40"
}
})
var angularPromise = $q.when(fetchPromise);
angularPromise.then(function (response) {
var test = response.json;
return response.json();
}).then(function (data) {
console.log('this is the data, ', data);
$scope.cards = data;
});
});
This is the code inside index.html that's supposed to show the result (relevant to quesiton)
<div ng-controller="minApiFunktionController">
<ul>
<li ng-repeat="item in cards">
<p>
<span>{{item.Basic.cardId}}</span>
</p>
</li>
</ul>
</div>
Just to clarify I got the controller imported and the index.html is including the module,
show this code to clarify that the controller is connected to my index.html page.
<html ng-app="produkterControllers">
maybe $scope.cards is not array, and not show in ng-repeat

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.

Having trouble on rendering data to angular

Currently I'm trying to render a specific data on angular with node/express as the backend.
What I'm trying to achieve is whenever a user clicks a specific story, it will link to that specific story page that belongs to a user who created the story.
api.js
apiRouter.get('/:user_name/:story_id', function(req, res) {
User.findOne({ name: req.params.user_name }, function(err, user, next) {
if(err) return next(err);
Story.findById(req.params.story_id, function(err, story) {
if(err) {
res.send(err);
return;
}
res.json({
name: user.name,
story_id: story._id,
content: story.content
});
});
});
});
As for the backend(api) It does show the specific data that I wanted with POSTMAN chrome tool but when it comes to angular I'm really confuse of how to render the data to the html.
service.js
storyFactory.getSingleStory = function(user_name, story_id) {
return $http.get('/api/' + user_name + story_id);
}
controller.js
angular.module('storyCtrl', ['storyService'])
.controller('StoryController', function(Story, $routeParams) {
var vm = this;
Story.getSingleStory($routeParams.user_name, $routeParams.story_id)
.success(function(data) {
vm.storyData = data;
});
});
app.routes.js
.when('/:user_name/:story_id', {
templateUrl: 'app/views/pages/users/single.html',
controller: 'StoryController',
controllerAs: 'story'
})
index.html ( Just going to show the line where it goes to the single.html )
<a href="/{{ main.user.name }}/{{ each._id }}"><h4>{{ each.content }}</h4>
single.html
Hello {{ main.user.name }}
<p>{{ story.content }}</p>
So far I couldn't manage to render the data properly with angular while with node/express I could query the data that I wanted with POSTMAN. I'm clueless and please save me from this confusion that angular giving me :)
I have went through your code, and you can improve in following parts:
Instead of using var vm = this in your controller, you should bind all objects to $scope, which is the key to two-way data binding. For instance
angular.module('storyCtrl', ['storyService'])
.controller('StoryController', function($scope, Story, $routeParams) {
var vm = this;
Story.all().success(function(data) {
$scope.stories = data;
});
Then stories can be accessed in View directly. It would be more readable than controllerName.stories in HTML.
<div class="col-md-6" ng-controller="StoryController as story">
<div class="panel-body" ng-repeat="story in stories">
<div class="comment-text">
<h4>{{ story.content }}</h4>
</div>
</div>
</div>
Keep in mind, then(function(response)) will only pass one parameter to the chained function while .success(function(data, status, headers, config)) will retrieve data from HTTP response. Then your code to load single story can be converted to
Story.getSingleStory($routeParams.user_name, $routeParams.story_id)
.then(function(data, status, headers, config) {
$scope.storyData = data;
});
Now we can access storyData in View.
There is a tiny bug in your Story Service. Change generateReq('GET', '/api/' + user_name + story_id) to generateReq('GET', '/api/' + user_name + '/' + story_id)
If you want to set values on the controller and see them in the html view. Set the view model on the controller's scope rather than using this. This and scope are not always the same thing and for binding I believe you need scope.
these expressions
// file: single.html
{{ main.user.name }}
<p>{{ story.content }}</p>
don't seem to be bound to any variable in 'StoryController'
Try using
// file: single.html
{{ story.storyData.user.name }}
<p>{{ story.storyData.content }}</p>
Your problem may be due to the fact that you story data is html and is therefore untrusted by default. For security reasons Angular will not allow you to render html directly into the page, instead you must explicitly tell Angular to trust the html content
To do this you must first include the ngSanitize module in your app.
angular.module('app', ['ngSanitize']);
You can then inject the $sce service which allows you to trust the html content. The code below has a data item with a property called Html that contains raw html text returned from an api. I just overwrite this raw html text with the $sce trust object returned from the $sce.trustAsHtml() method.
item.Html = $sce.trustAsHtml(item.Html);
Once you have trusted your html, you are now free to render it using the ng-bind-html attribute.
<div ng-bind-html="item.Html"></div>
For more information and further examples see:
Insert HTML into view using AngularJS
ngBindHtml

Angular JS/ Html queries on Ionic

Im working on a simple todo app tutorial online based on:
http://ionicframework.com/docs/guide/building.html
What if I wanted a database where instead of a fixed list like in the example, there would be a store where users can input their list dynamically, with room for edit and comments on their tasks outstanding?
a paragraph of text
user name noted
timestamp
It would then appear as a todo list that upon clicking, would open up to be editable and able to add more comments to it?
I have followed a couple of tutorials but all of them use fixed data sets.
I did some research and got the below snippets, my understanding of Angular is still weak so am not exactly clear how the codes work.
Something isnt working and Im not sure why. Can anyone explain and help?
Specifically on params and how id comes into play, as well as the convention of url routing, like #/something.html etc.
The tutorial has firebase back end but if you have any better suggestions (like server and back end language), please let me know. Ive seen tutorials using JSON but again, not sure how that works.
For app.js
.state('bucket.list.detail',{
url: '/list/:itemId',
views: {
'bucket-list-detail':{
templateUrl: 'templates/bucket-list-detail.html',
controller: 'DetailController'
}
}
})
For controller.js
.controller('DetailController', function($rootScope, $scope, $stateParams, $window, $firebase){
$scope.item = items.get($stateParams.itemId);
})
For the view file, bucket-list-detail.html
(I just typed in some trash lines to test the code)
<p>{{ item.item }}</p>
<p>
<a class="button button-small icon ion-arrow-left-b"
href="#/bucket/list"> Main List </a>
</p>
First in your question you have items.get in your controller but nowhere did you define items. Since $firebase is probably a factory of some kind you will probably need to either use that or build some service that is getting your data (via firebase or however).
As an example, I've built a sample todo app using .NET (web api) and Ionic that you can see the source code on github. The overall strategy for firebase should be similar.
I have a route like this, very similar to yours. This is for the details view:
.state('tab.tarea-detail', {
url: '/tarea/:tareaId',
views: {
'tab-friends': {
templateUrl: 'templates/_detalle.html',
controller: 'TareaDetailCtrl'
}
}
})
The state param will contain tareaId.
The list view has an ngRepeat with a link containing the id of a todo (tarea in spanish).
<ion-item ng-repeat="tarea in tareas track by $index" type="item-text-wrap" href="#/tab/tarea/{{tarea.Id}}">{{tarea.Nombre}} {{tarea.Desc}}
<ion-delete-button class="ion-minus-circled" ng-click="tareaEliminar(tarea)">
</ion-item>
And my controller which will receive the id and call a service:
.controller('TareaDetailCtrl', function($scope, $stateParams, tareaService) {
//tareaService is just a wrapper for my ajax stuff, you could call firebase here or you could just use firebase
tareaService.obtener($stateParams.tareaId).then(function (data)
{
$scope.tarea = data;
});
})
The service piece is just calling $http. This is a part of the service:
obtener: function (id)
{
var d = $q.defer();
$http.get(url + '/api/tareadata/obtener/' + id).success(function (data)
{
d.resolve(data);
}).error(function (data, error)
{
d.reject();
});
return d.promise;
}

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