I am new to angular and trying to integrate it within my application. I am attempting to use a simple ng-repeat (which works perfectly in an example project i setup). However, in the current project, i am using the Swig templating language, which fetches data from a .JSON file using {{ }} e.g:
person.html file:
<div> {{ myFirstName }} </div>
<div> {{ mySurName }} </div>
person.json file:
{
"myFirstName" : "Joe",
"mySurName" : "Bloggs",
}
I think the problem i am facing, is that Swig uses {{ }} to get data from .JSON files, and Angular uses {{ }} too.
Here is my simple ng-repeat:
<ul ng-controller="MyCtrl">
<li ng-repeat="country in countries">
{{country.name}} has population of {{country.population}}
</li>
</ul>
Here is my simple controller:
require(['app'], function(app) {
'use strict';
app.controller("MyCtrl", function($scope) {
$scope.countries = [
{name: 'France', population: 63.1},
{name: 'United Kingdom', population: 61.8}
];
});
});
When opening my HTML page, all that is displayed is:
has population of
has population of
Any ideas of how i can get around this?
Thanks
UPDATE
I would like angular to retrieve the data from the .JSON file
UPDATE Folloiw David Beech's recommendation
Application Tree:
- application
- resources
- CSS
- img
- JS
- data
- countries-data.json
- pages
- countries.html
In the example solution below my $http.get was
$scope.countries = [];
$http.get('/resources/data/countries-data.json', function(data){
Error shown in Firebug: "NetworkError: 404 Not Found - http: // localhost:8000/resources/data/countries-data.json"
To answer part 2 of your question and get angular to retrieve the json file use the $http service. http://docs.angularjs.org/api/ng/service/$http
app.controller("MyCtrl", function($scope, $http) {
$scope.countries = [];
$http.get('/path/to/data.json', function(data){
$scope.countries = data;
}, function(error) {
//handle error here
});
});
And to answer part 1:
I'm not familiar with swig and after a quick google I notice this is available server-side on node or client side and you don't specify how you are using it.
If you are using it server-side I would recommend you check it's documentation about escaping certain bindings to ensure pages are being delivered with the bindings in the html (you can check this by 'view page source' option in chrome).
UPDATE: http://paularmstrong.github.io/swig/docs/api/#SwigOpts
I notice here you can set the varControls binding to something other then '{{' and '}}'.
If you are using it client side then I would ask why you need it at all.. angular works best when you give it as close to complete and exclusive control over the DOM as possible. I'm sure anything that is possible in most templating engines is possible in angular with a little more learning and training and there are plenty of resources for that if you just do a little googling.
Hope this helps.
You can change the start and end interpolation tags using interpolateProvider service.
angular.module('myApp', []).config(function($interpolateProvider){
$interpolateProvider.startSymbol('{[{').endSymbol('}]}');
}
);
http://docs.angularjs.org/api/ng.$interpolateProvider
Related
I've just started using VueJS and I'm really liking it! :) I would like to save the values in the querystring to a VueJS variable - this is something super simple in handlebars + express, but seems more difficult in Vue.
Essentially I am looking for something similar to -
http://localhost:8080/?url=http%3A%2F%2Fwww.fake.co.uk&device=all
const app = new Vue({
...
data: {
url: req.body.url,
device: req.body.device
}
...
});
Google seemed to point me to vue-router, but I'm not sure if that's really what I need/how to use it. I'm currently using express to handle my backend logic/routes.
Thanks,
Ollie
You can either to put all your parameters in hash of the url, e.g.:
window.location.hash='your data here you will have to parse to'
and it will change your url - the part after #
Or if you insist to put them as query parameters (what's going after ?) using one of the solutions from Change URL parameters
You can use URLSearchParams and this polyfill to ensure that it will work on most web browsers.
// Assuming "?post=1234&action=edit"
var urlParams = new URLSearchParams(window.location.search);
console.log(urlParams.has('post')); // true
console.log(urlParams.get('action')); // "edit"
console.log(urlParams.getAll('action')); // ["edit"]
console.log(urlParams.toString()); // "?post=1234&action=edit"
console.log(urlParams.append('active', '1')); // "?post=1234&action=edit&active=1"
Source:
https://davidwalsh.name/query-string-javascript
URLSearchParams
https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
https://github.com/WebReflection/url-search-params/blob/master/build/url-search-params.js
See also:
https://stackoverflow.com/a/12151322/194717
Let's say I have an MVC/WebAPI/AngularJS site that I'm running locally, e.g. ;
localhost/Test/
which I then want to move to
www.test.com
While local, I have a lot of references to various directories (jsfiles, etc) of the following format (in either JS or HTML files)
app.directive('rpdbSpinner', function() {
return {
restrict: 'E',
**templateUrl: '/Test/templates/directives/spinner.html',**
scope: {
isLoading:'='
}
}
})
when updating/web publishing, I'd have to change everything to:
app.directive('rpdbSpinner', function() {
return {
restrict: 'E',
**templateUrl: '/templates/directives/spinner.html',**
scope: {
isLoading:'='
}
}
})
I can do this manually (which is what I've been doing),but the larger the project grows, the harder it becomes. I could, of course, only change it once and then excluded the files during publishing phase (web.config/rest), but it still feels like I am going about it the wrong way. Using "~/" wouldn't work on plain HTML/JS files as far as I'm aware, and this I can't really use it...
Any suggestions to map to paths globally regardless of whether in a Virtual Directory or the root of a project?
Thanks :)
If you simply care about getting the root/base url of the site so you can append that to get the other url you are after, you may simply use / as the first character of your url.
var getUsersUrl = "/api/users";
Here is an alternate approach if you want more than just the app root (Ex : Specific urls( built using mvc helper methods such as Url.RouteUrl etc)
You should not hard code your app base path like that. You may use the Url.Content or Url.RouteUrl helper methods in your razor view to generate the url to the app base. It will take care of correctly building the url regardless of your current page/path.Once you get this value, assign it to a javascript variable and use that in your other js code to build your other urls. Always make sure to use javascript namespacing when doing so to avoid possible issues with global javascript variables.
So in your razor view (Layout file or specific view), you may do this.
<script>
var myApp = myApp || {};
myApp.Urls = myApp.Urls || {};
myApp.Urls.baseUrl = '#Url.Content("~")';
myApp.Urls.userListUrl = '#Url.Action("Index","User")';
</script>
<script src="~/Scripts/NonAngularJavaScript.js"></script>
<script src="~/Scripts/AngularControllerForPage.js"></script>
<script>
var a = angular.module("app").value("appSettings", myApp);
</script>
In your angular controller, you can access it like,
var app = angular.module("app", []);
var ctrl = function (appSettings) {
var vm = this;
console.log(appSettings.Urls.userListUrl);
vm.baseUrl = appSettings.Urls.baseUrl;
//build other urls using the base url now
var getUsersUrl = vm.baseUrl + "api/users";
console.log(getUsersUrl);
};
app.controller("ctrl", ctrl)
You can also access this in your data services, directives etc.
In your non angular java script files.
// With the base url, you may safely add the remaining url route.
var urlToJobIndex2= myApp.Urls.baseUrl+"jobs/GetIndex";
Using "~/" wouldn't work on plain HTML/JS files as far as I'm aware,
and this I can't really use it...
Yes, but you could inject it in your main server-side served webpage as a variable:
<script>
var baseUrl = ... get the base url from the server using ~/
</script>
and then in your external scripts simply concatenate the relative urls with it. As far as static html files are concerned, then it could be a little more problematic. You could serve them through some special server side handler that will take care of injecting this logic.
You can use module.constant to create an injectable which you can use.
app.constant("URL_BASE", "/Test");
app.directive('rpdbSpinner', function(URL_BASE) {
return {
restrict: 'E',
**templateUrl: URL_BASE + '/templates/directives/spinner.html',**
scope: {
isLoading:'='
}
}
})
You can also use module.value if you register it before you register your directive.
For more information see AngularJS Module Guide -- configuration.
I'm trying to have Angular query a JSON file instead of using an http request in an Ionic project.
I'm working with the Ionic tutorial found here: https://ccoenraets.github.io/ionic-tutorial/index.html
I have gone through the entire tutorial and am "tinkering" which started with me wanting to change the data source from being an http request to a local JSON file and I've been partially successful.
All of the code I have in the project matches exactly what's seen in the tutorial with the following exception.
In the tutorial on "Module 4: Creating the Session Service," I changed this block seen in Step 3:
angular.module('starter.services', ['ngResource'])
.factory('Session', function ($resource) {
return $resource('http://localhost:5000/sessions/:sessionId');
});
To be:
angular.module('starter.services', ['ngResource'])
.factory('Session', function ($resource) {
return $resource('data/sessions.json');
});
To create the JSON file I took the return value of the http request seen in the tutorial and pasted it into the file referenced in the code and it is valid JSON.
Now, when I run the project (in a desktop browser or emulator), I am able to see the list of Sessions that was read from the JSON as expected. However, when I click/tap one of the Sessions to see the detail, the UI appears but has no data. When using the original code that gets the data via http I can see the detail.
This is the controller in my code that matches the tutorial, which presumably is where the problem lies:
.controller('SessionCtrl', function($scope, $stateParams, Session) {
$scope.session = Session.get({sessionId: $stateParams.sessionId});
})
Here is the HTML for that view:
<ion-view view-title="Session">
<ion-content>
<div class="list card">
<div class="item">
<h3>{{session.time}}</h3>
<h2>{{session.title}}</h2>
<p>{{session.speaker}}</p>
</div>
<div class="item item-body">
<p>{{session.description}}</p>
</div>
<div class="item tabs tabs-secondary tabs-icon-left">
<a class="tab-item">
<i class="icon ion-thumbsup"></i>
Like
</a>
<a class="tab-item">
<i class="icon ion-chatbox"></i>
Comment
</a>
<a class="tab-item">
<i class="icon ion-share"></i>
Share
</a>
</div>
</div>
</ion-content>
</ion-view>
Here is the error in the console after clicking through to the Session detail view:
Error: [$resource:badcfg] get
http://errors.angularjs.org/1.3.13/$resource/badcfg?p0=object&p1=array
at REGEX_STRING_REGEXP (http://localhost:8100/lib/ionic/js/ionic.bundle.js:8762:12)
at d.module.provider.$get.e.(anonymous function).q.then.p.$resolved (http://localhost:8100/lib/ionic/js/angular/angular-resource.min.js:9:330)
at processQueue (http://localhost:8100/lib/ionic/js/ionic.bundle.js:21888:27)
at http://localhost:8100/lib/ionic/js/ionic.bundle.js:21904:27
at Scope.$get.Scope.$eval (http://localhost:8100/lib/ionic/js/ionic.bundle.js:23100:28)
at Scope.$get.Scope.$digest (http://localhost:8100/lib/ionic/js/ionic.bundle.js:22916:31)
at Scope.$get.Scope.$apply (http://localhost:8100/lib/ionic/js/ionic.bundle.js:23205:24)
at done (http://localhost:8100/lib/ionic/js/ionic.bundle.js:18358:47)
at completeRequest (http://localhost:8100/lib/ionic/js/ionic.bundle.js:18548:7)
at XMLHttpRequest.requestLoaded (http://localhost:8100/lib/ionic/js/ionic.bundle.js:18489:9)
And here's the data where the Session list comes from and it's also the data I want to query:
[{"id":0,"title":"Introduction to Ionic","speaker":"CHRISTOPHE COENRAETS","time":"9:40am","room":"Ballroom A","description":"In this session, you'll learn how to build a native-like mobile application using the Ionic Framework, AngularJS, and Cordova."},{"id":1,"title":"AngularJS in 50 Minutes","speaker":"LISA SMITH","time":"10:10am","room":"Ballroom B","description":"In this session, you'll learn everything you need to know to start building next-gen JavaScript applications using AngularJS."},{"id":2,"title":"Contributing to Apache Cordova","speaker":"JOHN SMITH","time":"11:10am","room":"Ballroom A","description":"In this session, John will tell you all you need to know to start contributing to Apache Cordova and become an Open Source Rock Star."},{"id":3,"title":"Mobile Performance Techniques","speaker":"JESSICA WONG","time":"3:10Pm","room":"Ballroom B","description":"In this session, you will learn performance techniques to speed up your mobile application."},{"id":4,"title":"Building Modular Applications","speaker":"LAURA TAYLOR","time":"2:00pm","room":"Ballroom A","description":"Join Laura to learn different approaches to build modular JavaScript applications."}]
I can't seem to get my head wrapped around why changing the http request to a local file does not work for the query performed in 'SessionCtrl'.
What changes need to be made so the detail view will work?
UPDATE
Following the suggestion from #ErnestoRendon I think I have made progress.
I changed the factory to look like this:
angular.module('starter.services', ['ngResource'])
.factory('Session', function ($resource) {
return $resource('data/sessions.json',{ }, {
getData: {method:'GET', isArray: false}
});
});
And the controller has been updated to look like this:
.controller('SessionCtrl', function($scope, $stateParams, Session) {
$scope.session = Session.getData({sessionId : $stateParams.sessionId});
console.log($stateParams.sessionId); // This DOES log the correct option selected from the list
})
When leaving isArray set to false I get the same object/array error when getData() is called. When I change isArray to "true" the error goes away but no data is returned to the UI. This is the error when setting that value to "false": http://errors.angularjs.org/1.3.13/$resource/badcfg?p0=object&p1=array
In either scenario (isArray being "true" or "false") the correct sessionId will log to the console from the controller.
So while things appear to be better when setting isArray to "true," I'm still not getting data into the UI.
Here's an example that loads data from a JSON file similar to what you describe.
angular.module('starter.services', ['ngResource'])
.factory('Session', function ($resource) {
return $resource('data/sessions.json',{ }, {
getData: {method:'GET', isArray: false}
});
});
Notice that isArray is set to false.
I am learning angularjs and following tutorial from - here
Here is my index.jsp -
<!doctype html>
<html lang="en" ng-app="phoneCatApp">
<head>
<title>Angular Example</title>
<script type="text/javascript" src="angular/angular.min.js"></script>
<script type="text/javascript" src="app/js/controllers.js"></script>
</head>
<body ng-controller="phoneListCtrl">
Search : -
<input ng-model="query"/> Sort by:
<select ng-model="orderProp">
<option value="name">Alphabetical</option>
<option value="age">Newest</option>
<option value="-age">Oldest</option>
</select>
<p>Total number of phones: {{phones.length}}</p>
<ul>
<li ng-repeat="phone in phones | filter:query | orderBy:orderProp"><span>{{phone.name}}</span>
<p>{{phone.snippet}}</p></li>
</ul>
</body>
</html>
this version of controller.js works -
var phonecatApp = angular.module('phoneCatApp', []);
phonecatApp.controller('phoneListCtrlOld', function($scope) {
$scope.phones = [ {
'name' : 'Nexus S',
'snippet' : 'Fast just got faster with Nexus S.',
'age' : 1
}, {
'name' : 'Motorola XOOM™ with Wi-Fi',
'snippet' : 'The Next, Next Generation tablet.',
'age' : 2
}, {
'name' : 'MOTOROLA XOOM™',
'snippet' : 'The Next, Next Generation tablet.',
'age' : 3
} ];
$scope.orderProp = 'age';
});
but in the next step i tried fetching this json data with ajax call so controller look like this -
var phonecatApp = angular.module('phoneCatApp', []);
phonecatApp.controller('phoneListCtrl', function($scope, $http) {
$http.get('app/js/phones.json').success(function(data) {
$scope.phones = data;
});
$scope.orderProp = 'age';
});
But this gives me following error -
TypeError: dbg is undefined. debuggerLib.js (line 530)
I can see in firebug the ajax call is happening with code 304 Not Modified. and i can see data in response. but response content type is not json.
Please look into it and say what is the problem? Am i missing any js file to include or something else.
I have had this same error, and after some head scratching found a cause. I can't be sure whether this is your same cause.
Restarting Firefox, rebooting the PC, removing Firebug, reinstalling, optimizing, running registry clean, etc. -- nothing helped. I got error in debuggerLib.js line 556, dbg being undefined.
However, it turns out that I have installed Firebug back in the days, and it created a directory in my Roaming profile:
C:\Users\Leonardo\AppData\Roaming\Mozilla\Firefox\Profiles\Leonardo.Serni\firebug
In that directory there is a lot of JSON files, but none of them dated today, which is when I removed and reinstalled Firebug. So I wondered, "What if the new Firebug is loading something obsolete from this directory?".
I closed Firefox, renamed the directory from "firebug" to "bugfire", reopened Firefox.
Firebug is running perfectly and the error has disappeared. I had done the same thing without renaming the directory and the error did not disappear, so I'm confident that my hypothesis was correct.
The directory has been re-created, but there are now only two files in there - "annotations.json" and "breakpoints.json", both 0 bytes in size. Possibly some day I'll try adding the files from the old directory to see when the error comes back.
Update (thanks to DevNull's comment)
Possibly it is not necessary to nuke the whole directory. Verify that the annotations.json file is zero length. If it is not, just rename it to annotations.old while Firefox is not running.
I'm beginning to suspect that the dbg is actually debugging Firebug itself, and we do not have it defined because we aren't Firebug developers. It has nothing to do with the Firebug debugger that debugs our scripts.
You're probably using FireFox with firebug activated.
Turn off firebug and your issue will go away.
I had the same problem, other browsers had no issue and the console showed the error coming from debuggerLib.js (line 556). Deactivating it removed the error and allowed my application to run as expected.
use this code html head tag.
<base href="/">
....
Try this,
First initialize JSON array value is an empty.so initialize
$scope.phones = '';
Explanation of #LSerni seems correct.
For Linux system simply remove and reinstall your Firebug plugin. The system auto deletes all related files/folders and recreates it.
This worked for me.
The error you are having is with your JSON file. It should look like this:
[{
"name" : "Nexus S",
"snippet" : "Fast just got faster with Nexus S.",
"age" : 1
}, {
"name" : "Motorola XOOM™ with Wi-Fi",
"snippet" : "The Next, Next Generation tablet.",
"age" : 2
}, {
"name" : "MOTOROLA XOOM™",
"snippet" : "The Next, Next Generation tablet.",
"age" : 3
}]
Remember the square brackets.
Use .then rather than .success. This is an improved version of .success handling all the callbacks and calls more efficiently. It brings back the entire promise and you resolve it by referencing the .data part i.e. response.data
$http.get('app/js/phones.json').then(function(response) {
$scope.phones = response.data;
});
DEMO - Using .success
DEMO - Using .then promise
You are using the number so please use number or parse value to number example below.
<code>
var myApp = angular.module('MyApp',[]);
myApp.controller("myController",function($scope){
$scope.width=50;
$scope.height=50;
});
</code>
for me the problem was that I had forgotten to define in the controller the library
app.controller("MyCtrl", function($scope, $http) { //<- here $timeout was missing
$http.get(someUrl)
.then(function(myResponse) {
$scope.myData = myResponse.data;
$timeout(function() { //<- here $timeout was called without being defined
enableWatchers = true;
});
});
});
It works after I have changed the first line of my code to:
app.controller("MyCtrl", function($scope, $http, $timeout) { //<- here I put the $timeout
In a php file I can do:
<p><?php echo "hello!";?></p>
Is there a way to do this in node, if yes what's the logic for it?
I have an idea how could this be done:
Use an identifier markup for node in the HTML file like: <node>code</node>
Load & Parse HTML file in Node
Grab node markup from the HTML file and run it
But I'm not sure if this is the best way or even if it works :)
Please note I want to learn node.js, so express and other libraries and modules are not answers for me, because I want to know the logic of the process.
What your describing / asking for a node.js preprocessor. It does exist but it's considered harmful.
A better solution would be to use views used in express. Take a look at the screencasts.
If you must do everything from scratch then you can write a micro templating engine.
function render(_view, data) {
var view = render.views[view];
for (var key in data) {
var value = data[key];
view.replace("{{" + key + "}}", value);
}
return view;
}
render.views = {
"someView": "<p>{{foo}}</p>"
};
http.createServer(function(req, res) {
res.end(render("someView", {
"foo": "bar"
}));
});
There are good reasons why mixing php/asp/js code directly with HTML is bad. It does not promote seperation of concerns and leads to spaghetti code. The standard method these days is templating engines like the one above.
Want to learn more about micro templating? Read the article by J. Resig.
You can try using JooDee, a node webserver which allows you to embed serverside javascript in your web pages. If you are familiar with Node and PHP/ASP, it is a breeze to create pages. Here's a sample of what a page looks like below:
<!DOCTYPE html>
<html>
<: //server side code in here
var os = require('os');
var hostname = os.hostname();
:>
<body>
<div>Your hostname is <::hostname:></div>
</body>
</html>
Using JooDee also lets you expose server javascript vars to the client with no effort by attaching attributes to the 'Client' object server side, and accessing the generated 'Client' object in your client side javascript.
https://github.com/BigIroh/JooDee
Use a template engine. From terminal
npm install ejs
In code:
var ejs = require('ejs');
var options = {
locals: {
foo: function() { return "bar"; }
}
};
var template = "<p><%= foo() %></p>";
console.log(ejs.render(template, options));