AngularJS Directive not reading data from controller - html

I am trying to learn about angular Directives and following the example given in here (http://docs.angularjs.org/guide/directive), have written the below code. Could anyone please guide me as what am i doing wrong that the data from the scope of the controller is not being read in the directive? The site says nothing about it! And there is no error upon executing the code, it just does not display any data. Please help.
//My Html
<!DOCTYPE html>
<html data-ng-app="MyApp">
<head>
<title>Angular Directives</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body >
<div data-ng-controller = "MyCtrl"></div>
<div data-template-expanding-directive></div>
<script src="lib/angular.js"></script>
<script src="js/templateExpandingDirective.js"></script>
</body>
</html>
//My JS
'use strict';
var myapp = angular.module('MyApp',[]);
myapp.controller('MyCtrl',['$scope',function($scope){
$scope.customer = {
name: "Jenny",
place: "England"
};
}])
.directive('templateExpandingDirective',function(){
return {
template: 'Name: {{customer.name}}'
};
});
Regards

The directive is currently out of controller scope. So you need to have directive inside the controller scope. The html should be like this -
<div data-ng-controller = "MyCtrl">
<div data-template-expanding-directive></div>
</div>
If you do not move the directive element inside the controller div element then you can either have one more parent 'div' element or access the data from global root scope.

Related

Automatically filling certain parameters in an html file on hosted server with node js

I'm working on a project in which I have a simple web server hosted with node.js (see code below) and I want to be able to dynamically load the code form html files and modify them each time someone makes a request. I've already putted some marker in my code ${likeThis} and I just need the code to put a string in the right place.
Here is my server code:
const express = require('express');
const app = express();
app.get('/', function (req, res) {
res.send('Hello World');
})
app.listen(8080);
});
And here is an example page in which I want to change the value ${sampleText} with the plain text "hello world!!!":
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<head>
<title>Titler</title>
</head>
<body>
${sampleText}
</body>
Mind that there might be more of the same or different kind of value all over the html page.
On the user side I'd expect this:
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<head>
<title>Titler</title>
</head>
<body>
Hello world!!!
</body>
There are several ways to use live data in pages returned from express. All of them utilize a "template" into which you inject "data". These include:
pug
mustache
handlebars
Another option would be to use NodeJS/ES6 template strings, such as:
const express = require('express')
const app = express()
// Text to insert into template
const sampleText = 'hello world!!!'
// Template to accept sampleText
const result = `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Titler</title>
</head>
<body>
${sampleText}
</body>
</html>
`
app.get('/', function (req, res) {
res.send(result);
})
app.listen(8080);
Backticks ("`") are used to define template strings in Node where "${expression}" is used to insert any evaluable JavaScript expression into a template, like:
const result = `The contents of file ${filepath} are: ${fs.readFileSync(filepath).toString()}`
For more information, see Using Template Engines with Express
and for an exhaustive list of template engines that work "out of the box" with Express see Template Engines
i ll illustrate with Mustache, you need webpack for communication between front-side and web-server, but since webpack is headache i ll use mustache CDN.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<div id="message"></div>
//we are gonna render the message into this div tag.
//this is a javascript code
//make sure script tags are at the bottom
<script id="message-template" type="text/html">
<div class="message">
{{message}} . //yes double curly brackets
</div>
</script>
//CDN link, Mustache pack files are stored here and we import from there
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/3.0.1/mustache.min.js"></script>
//for src add path of index.js in your app
<script src="./index.js"></script>
</body>
</html>
index.js
//select the div that you wanna place the message
const $message = document.querySelector("#messages");
//select the script tag in
const messageTemplate = document.querySelector("#message-template").innerHTML;
const html = Mustache.render(messageTemplate, {
//I hardcoded the message here, but as you learn, you will catch a dynamic data, put it here and display in your html page
message:"hello world",
});
$message.innerHTML(html);
After a bit of work(very flew actualy) i monaged to make this function that allows me to find the strings and replace them with the correct text, i will publish it hoping someone else in the future migth need it:
function substituteString(input, stringToChange, substitute) {
var n = 0;
while (true) {
n = input.indexOf(stringToChange, n);
if (n == -1) { break; } else {
input = input.replace(stringToChange ,substitute);
}
}
return input;
}
Easier than i was thinking

Why I can't just access the root-scope variable in the HTML's <script> </script> part?

I am a newbie to AngularJs and I am building a simple AngularJs web, I have set up the page and it works as I expect. But when I try to use the rootscope variable in the script part of my index.html. it always give an error: the variable is not define. However, I can still use the variable in the html part of the index.html. Can anyone tell me why it works like this? and how to resolve it?
Thanks.
Here is my simple HTML Code:
<!DOCTYPE html>
<html data-ng-app="test" lang='laCo'>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge; IE=10; IE=9">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet"
href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$( function() {
loaddivpage();
});
loaddivpage = function(){
window.Final = user.userId;
$( "#innerdiv" ).load("./app/chat/Dialog.html");
}
</script>
</head>
<body>
<div id ="webdiv">
<div id = "innerdiv"> </div>
</div>
</body>
</html>
Here I want to load a Dialog.html into the innerdiv, which uses the window.Final variable. Note: user.userId is the rootscope variable.
I manage to find a way to do, since the html part has connection with the root scope, so I can use angular to fetch the root scope variable:
Like: By using angular.element($("#your div id ")).scope() to get scope of the html part, and then use this scope to access the root scope variable. Hope this will help someone else.

AngularJS variable not changing back in controller

js:
$scope.hello = "hello world";
html:
<input ng-model="hello">
<label>{{hello}}</label>
It sets the label good on initializing but after that it stop updating. What's wrong?
Try to use this in your controller:
$scope.system = {};
$scope.system.hello = 'hello world';
Here you Go
as per your code there were no clues for errors so i just answered with working code and some definition of 2-way data-binding
The updating is called two-way binding a good feature from angular .
Little Brief about 2 way data binding :-
Two way data binding in angularjs framework is approach to synchronize
the data between model and view. What it means that if there is any
change happens in model ( Back-end ) then view ( front-end ) will be
updated and vice versa.
data binding docs Angular data binding Documentation
Sample Js: -
'use strict';
var app = angular.module('mainApp', []);
app.controller('registerCtrl', ['$scope', function($scope){
$scope.hello='hello world';
}]);
Html :-
<!DOCTYPE html>
<html ng-app="mainApp">
<head>
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-controller="registerCtrl">
<input type="text" ng-model="hello"/>
{{hello}}
</body>
</html>
You properly Binded to the text box with model
plunker https://plnkr.co/edit/go9r3x?p=preview

AngularJS trouble adding page titles

I am writing a web app using AngularJS. It is not a single page application but all my codes are in one file- index.ejs.
So my set up for index.ejs roughly looks like this:
<head>
<title> Main page </title>
</head>
<body>
<div class="row">
<div class="col-md-10 col-md-offset-1">
<ui-view></ui-view>
</div>
</div>
<script type = "text/ng-template" id = "/main.html">
.....
</script>
<script type = "text/ng-template" id = "/addStuff.html">
.....
</script>
<script type = "text/ng-template" id = "/searchStuff.html">
.....
</script>
<script type = "text/ng-template" id = "/about.html">
.....
</script>
</body>
I have a title for the main page on top of index.ejs. I would also like to have seperate titles for each page so when they are opened in a new tab, I know which one is which. I have tried doing:
<script type = "text/ng-template" id = "/addStuff.html">
<head>
<title> Add Stuff </title>
</head>
.....
But this doesn't work. Any ideas? Thanks.
You should use ui-router. In which case you can add a top level controller on the body or html element, for example <html ng-app="my-app" ng-controller="AppCtrl">
And add a '$stateChangeSuccess' listener whenever a new route is loaded...
.controller('AppCtrl', function AppCtrl($scope) {
$scope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
if (angular.isDefined(toState.data.pageTitle)) {
$scope.pageTitle = toState.data.pageTitle;
}
});
})
Then in the route definition you can add a property called data.pageTitle
$stateProvider.state( 'profile', {
url: '/profile',
views: {
"main": {
controller: 'ProfileCtrl',
templateUrl: 'profile/profile.tpl.html'
}
},
data:{
pageTitle: 'Profile'
}
})
Then in your main index.html file, you can bind the pageTitle attribute:
<title ng-bind="pageTitle"></title>
The most important part is the you move the directive ng-app on the <html> tag if it's not already in there.
Thus all the html page is covered by angular.
Eg:
<html ng-app="app">
...
</html>
Then it's really your choice.
You can use a custom directive to wrap the title, generate a service or just use the {{ }} syntax.

angularjs directive displays json during page load

I'm building my first AngularJS dynamic form, built based on information received from a JSON file using AngularJS directive.
Everything works, my issue is that the JSON code is getting displayed while the page is loaded - once the page is loaded the JSON code disappears.
Am I doing something wrong?
Check http://plnkr.co/edit/v4jOwuF6jmZfORlNbvIB?p=preview to see the behavior, click on "Stop"/"Start" multiple times to see the behavior.
HTML code:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script data-require="angular.js#*" data-semver="1.4.0-beta.2" src="https://code.angularjs.org/1.4.0-beta.2/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="ViewCtrl">
<div ng-repeat="page in form.form_pages">
<div ng-repeat="field in page.page_fields" class="form-group">
<field-directive field="field" ng-form="subForm"></field-directive>
</div>
</div>
</body>
js code:
'use strict';
angular.module('myApp',[])
.controller('ViewCtrl', ['$scope', function($scope) {
var jsonStr='{"form_id":"1","form_name":"My Test Form","form_pages":{"1":{"page_id":1,"page_title":"My First Tab","page_hide":false,"page_fields":{"1":{"field_id":1,"field_title":"First Name","field_type":"textfield","field_value":"","field_required":true,"field_disabled":false},"2":{"field_id":2,"field_title":"Last Name","field_type":"textfield","field_value":"","field_required":true,"field_disabled":false},"3":{"field_id":3,"field_title":"Gender","field_type":"textfield","field_value":"0","field_required":true,"field_disabled":false},"4":{"field_id":4,"field_title":"Email Address","field_type":"textfield","field_value":"","field_required":true,"field_disabled":false},"5":{"field_id":5,"field_title":"Password","field_type":"textfield","field_value":"","field_required":true,"field_disabled":false},"6":{"field_id":6,"field_title":"Birth Date","field_type":"textfield","field_value":"1981-01-10T06:00:00.000Z","field_required":true,"field_disabled":false},"7":{"field_id":7,"field_title":"Your browser","field_type":"textfield","field_value":"2","field_required":false,"field_disabled":false},"8":{"field_id":8,"field_title":"Additional Comments","field_type":"textarea","field_value":"","field_required":true,"field_disabled":false},"9":{"field_id":9,"field_title":"I accept the terms and conditions.","field_type":"textfield","field_value":"0","field_required":true,"field_disabled":false}}}}}';
$scope.form = JSON.parse(jsonStr);
}])
.directive('fieldDirective',function($http, $compile) {
var linker = function(scope, element) {
// GET template content from path
var templateUrl = "textfield.html";
$http.get(templateUrl).success(function(data) {
element.html(data);
$compile(element.contents())(scope);
});
}
return {
template: '<div>{{field}}</div>',
restrict: 'E',
scope: {
field: '='
},
link: linker
};
})
textfield.html - the html template:
<div class="row" ng-form="subForm" ng-class="{'has-success': subForm[field.field_id].$invalid}">
<div class="col-sm-5">{{field.field_title}}:</div>
<div class="col-sm-7">
<input type="text"
placeholder="{{field.field_title}}"
ng-model="field.field_value"
value="{{field.field_value}}"
ng-required="field.field_required"
ng-disabled="field.field_disabled"
class="form-control"
id = "{{field.field_id}}"
name = "{{field.field_id}}" >
<div ng-show="subForm[field.field_id].$touched && subForm[field.field_id].$error && subForm[field.field_id].$invalid">Field '{{field.field_title}}'
<span ng-show="subForm[field.field_id].$error.required"> is required.</span>
</div>
</div>
</div>
Thank you.
http://plnkr.co/edit/YC9p0UluhHyEgAjA4D8R?p=preview
Basically instead of adding the loaded template into the element then compiling it in place I just compile the string then insert the compiled element directly
element.append($compile(data)(scope));
Seems you can still see a delay but this might be the async loading of the template causing that, would need to debug in the network panel and do some profiling or logging to see exactly what's going on.
Edit
Made a fork of the plnkr to show one with the template inlined so there's no delay fetching it with $http http://plnkr.co/edit/Tnc3VOeI8cELDJDHYPTO?p=preview instead just grabbing it synchronously from the template cache and using ng-template in a script block to have it loaded in advance.