AngularJs Model changes don't update - javascript

I have a model that I want to be editable, but for some reason nothing change, the textbox doesn't show up and the model is not being updated when using ng-view.
I can see the function enableEditor() being called using console.log.
If I write it inline instead of ng-view in the index.html without the profile.html everything works perfectly.
here are the files:
app.js
var proGamersApp = angular.module('proGamersApp', ['ngResource']).
config(function ($routeProvider) {
$routeProvider.
when('/', { controller: 'ProfileController', templateUrl: '/app/partials/profile.html' }).
otherwise({ redirectTo: '/' });
});
var ProfileController = function ($scope) {
$scope.init = function () {
$scope.title = 'first title';
};
$scope.init();
$scope.enableEditor = function () {
console.log('enableEditor()')
$scope.editorEnabled = true;
$scope.editableTitle = 'second title';
$scope.title = 'second title';
};
...
};
index.html
<!doctype html>
<html ng-app="proGamersApp">
<head>
<title>Pro Gamers</title>
<!-- Scripts -->
<script src="/app/lib/angular.min.js"></script>
<script src="/app/lib/angular-resource.js"></script>
<script src="/app/app.js"></script>
</head>
<body>
<div ng-view></div>
</body>
</html>
profile.html
<div ng-hide="editorEnabled">
{{title}}
Edit title
</div>
<div ng-show="editorEnabled">
<input ng-model="title" ng-show="editorEnabled">
Save
or
cancel.
</div>
Does someone know what I am doing wrong?
thanks

The link is adding to your address, causing the router to refresh the page and wack all your $scope vars. Instead of using blank anchors, use a span styled like an anchor:
span:hover {
cursor:pointer;
}
This only gives the cursor the pointer finger, customize the colors as you wish. Per your comments as well, don't add the target=_self to the href, add it after:
Save //prevent address bar change
As I said before though, use spans instead.

Related

How to add some loading message in angularjs every route changes

Im new to angularjs and Im currently learning on angular's ng-route. I already done on it but what I want to achieve is to display first the loading message before displaying the content of the address of the route.
What's happening on my code right now is like this:
1. Click the home link
2. Display the loading message on the current page before successfully loading the content of the home link
That's how my code works, and I don't want it that way.
What I want to happen is something like this:
1. Click the home link
2. Current page will be hidden and display the loading message before displaying the content of the home link
I hope you understand. By the way here's my code:
index.html
<body ng-app="myApp" ng-controller="mainController">
<i class="fa fa-shield"></i> main
<i class="fa fa-home"></i> home
<!-- start views -->
<div ng-view></div>
</body>
script.js
var app = angular.module('myApp', ['ngRoute']);
app.config(function($routeProvider){
$routeProvider
.when('/',{
templateUrl: 'main.html',
controller: 'mainController',
resolve:{
delay: function($q, $timeout){
var delay = $q.defer();
$timeout(delay.resolve, 1000);
return delay.promise;
}
}
})
.when('/home',{
templateUrl: 'home.html',
controller: 'homeController',
resolve:{
delay: function($q, $timeout){
var delay = $q.defer();
$timeout(delay.resolve, 1000);
return delay.promise;
}
}
})
.otherwise({
redirectTo: '/'
});
});
app.controller('mainController', function($scope){
$scope.message = "...";
});
app.controller('homeController', function($scope){
$scope.message = "...";
});
app.directive('showDuringResolve', function($rootScope) {
return {
link: function(scope, element) {
element.addClass('ng-hide');
var unregister = $rootScope.$on('$routeChangeStart', function() {
element.removeClass('ng-hide');
});
$scope.$on('$destroy', unregister);
}
};
});
main.html
<h1>Main Page</h1>
<div show-during-resolve class="alert alert-info">
<strong>Loading.</strong>
Please hold.
</div>
home.html
<h1>Home Page</h1>
<div show-during-resolve class="alert alert-info">
<strong>Loading.</strong>
Please hold.
</div>
you can achieve the desired behavior with few modification in your code.
Add the loader text in your index.html file and show/hide the ng-view and loading text based on the rootScope variable statechange
<div ng-view ng-show="statechange"></div>
<div ng-show="!statechange" show-during-resolve class="alert alert-info">
<strong>Loading.</strong>
Please hold.</div>
in your directive make the following change.
app.directive('showDuringResolve', function($rootScope) {
return {
link: function(scope, element) {
element.addClass('ng-hide');
$rootScope.statechange = true;
var unregister = $rootScope.$on('$routeChangeStart', function() {
element.removeClass('ng-hide');
$rootScope.statechange = false;
});
scope.$on('$destroy', unregister);
}
};
});
Plunker : https://plnkr.co/edit/RISv2lvxwf75nuVfWLgA?p=preview
You can use a variable in each controller like dataReady, so for example in your home page, you can do something like:
html:
<div ng-show="dataReady">
<h1>Home Page</h1>
<div show-during-resolve class="alert alert-info">
<strong>Loading.</strong>
Please hold.
</div>
</div>
<div ng-show="!dataReady">
<h1> Loading ...</h1>
</div>
js:
app.controller('homeController', function($scope){
$scope.message = "...";
// After all the logic
$scope.dataReady = true;
});
And repeat the same idea for all the pages that you need.
By default set the loader to be hide
<strong class="loader" id="loader">Loading....</strong>
.loader{
display: none;
}
.loader-show{
display: inline-block;
}
When request made to get data, show the loader by adding loader-show class. On successful completion of request, hide loader by removing loader-show class.
That is,
resolve:{
delay: function($q, $timeout){
var loader = document.getElementById('loader');
loader.addClass('loader-show'); // when request is going to made
var delay = $q.defer();
$timeout(delay.resolve, 1000);
loader.removeClass('loader-show'); // when request ends
return delay.promise;
}
}

Javascript inside a Angular router

I have build a very basic Angular Router. But now that I want to interact with my elements inside that templateUrl, no javascript gets executed or those elements inside the templateUrl can not be accessed. I have copied the most of the code from this instruction, here.
My index file:
<html ng-app="myApp">
<head></head>
<body ng-controller="mainController">
<a id="btnHome" href="#/">Startseite</a>
<a id="btnPlanner" href="#/planner">LTC-Planner</a>
<a id="btnSocial" href="#/social">LTC-Social</a>
<div id="main">
<!-- angular content -->
<div ng-view></div>
</div>
<script src="js/routing.js"></script>
</body>
</html>
This is my routing.js file:
// Create the angular module
var myApp = angular.module('myApp', ['ngRoute']);
// Configure our routes
myApp.config(function($routeProvider) {
$routeProvider
// Route for the home page
.when('/', {
templateUrl: 'pages/home.html',
controller: 'mainController'
});
});
// Create the controller and inject angular's $scope
myApp.controller('mainController', function($scope) {
$scope.message = 'This is the HOME page';
});
and this is the template file located at pages/home.html:
<button id="btnTest">Say Hello</button>
<script>
var btnTest = document.getElementById('btnTest');
btnTest.addEventListener('click', function(){
console.log('Hello');
});
</script>
maybe one of you got an idea or has seen an alternative.
Thanks,
André
you should try to wrap your html template in a single tag
<div>
<button ng-click="test()">Say Hello</button>
</div>
And remove the script to put the logic inside your controller. Since your using angular, just use ng-click to bind click listener.
myApp.controller('mainController', function($scope) {
$scope.message = 'This is the HOME page';
$scope.test = function() {
console.log('Hello');
}
});

AngularJS routeprovider is not called

I've googled a lot of info about routing in AngularJS and have seen questions at stackoverflow, for example, this 1, this 2, this 3, this 4. However, there is no result.
I've included AngularJS 1.5.8.js and angular-route.js.
HTML:
<!doctype html>
<html ng-app="employeesApp">
<head>
<title>Injecting view</title>
</head>
<body >
<p>Hey! View should be injected between these statements</p>
<div ng-view></div>
<p>Hey! View should be injected between these statements</p>
<script src="scripts/angular.js"></script>
<script src="scripts/angular-route.js"></script>
<script src="app/app.js"></script>
<script src="app/controllers/employeesController.js"> </script>
</body>
</html>
Employees.html:
<h2>Employees</h2>
<article>This is employee view!:)</article
employeesController.js:
(function()
{
var employeesController=function($scope, foo, bar) {//THIS CODE SNIPPET IS NOT CALLED
alert('a1');
debugger;
$scope.sortBy='name';
$scope.reverse=false;
$scope.employees= [
{joined:'2010-12-02', name:'Jon', city:'Reading', orderTotal:49.9956},
{joined:'1995-01-25', name:'Ben', city:'Las Vegas', orderTotal:519.99},
{joined:'1994-06-15', name:'Joseph', city:'New York', orderTotal:344.99},
{joined:'1998-03-18', name:'Adam', city:'Seattle', orderTotal:1021.5}
];
$scope.doSort=function(propName){
$scope.sortBy = propName;
$scope.reverse=!$scope.reverse;
};
};
employeesController.$inject=['$scope'];
angular.module('employeesApp',[]).controller('employeesController',
employeesController);
}());
app.js:
(function() {
debugger; //this code snippet works
var app=angular.module('employeesApp',['ngRoute']); //this code snippet works
app.config(function($routeProvider){ //THIS CODE SNIPPET IS NOT CALLED
alert('in');
debugger;
$routeProvider
.when('/', {
templateUrl: 'app/views/employees.html',
controller: 'employeesController'
})
.otherwise( { redirectTo: '/' });
});
}());
I double checked all directives and code, however employee.html is not injected.
Does anybody know what I am doing wrong? I am using AngularJS 1.5.8.js.
The only problem i see is you are redefining employeesApp in your controller
angular.module('employeesApp', []).controller('employeesController', employeesController);
Omit the [] part
angular.module('employeesApp').controller('employeesController', employeesController);
You only define your modules once. Using angular.module('modulename', arrayofdependencies or empty array)
Everywhere else you just get the module and add parts, i.e. Controllers, directives etc, using getter syntax. Do not use array here. angular.module('modulename').controller

Compile kendo window after refresh content

I have a single kendo-window in my page and i want to load content to it every time i click a command. The content i want to load is either from x-kendo-template or from .html with expression in angular {{Sample}}. After the content is loaded, i tried to $compile the content to make use of the angular binding but it is not working. This is what i tried so far
On my markup
<base href="http://demos.telerik.com/kendo-ui/grid/angular">
<script id="tplAddNew" type="text/x-kendo-template">
Action in Add New: {{ Action }}
</script>
<script id="tplView" type="text/x-kendo-template">
Action in View: {{ Action }}
</script>
<div id="example" ng-app="Test">
<div ng-controller="MyCtrl">
<div kendo-window="winTesting"
k-visible="false"
k-modal="true"
k-pinned="true"
k-width="'500px'"
k-min-height="'200px'">
</div>
<button
kendo-button
ng-click="AddEntry()">Add Entry</button>
<button
kendo-button
ng-click="ViewContent()">View Content</button>
</div>
</div>
and here is my controller
var app = angular.module("Test", ["kendo.directives"]);
app.controller("MyCtrl", [
"$scope", "$compile",
function($scope, $compile) {
$scope.AddEntry = function() {
$scope.Action = "Add New";
$scope.winTesting
.refresh({
//url: '../References/Test-entry.html'
template: kendo.template($('#tplAddNew').html())
})
.setOptions({
title: "Create New User"
});
//$scope.$apply(function() {
// $compile($scope.winTesting.element)($scope);
//});
$scope.winTesting.open().center();
}
$scope.ViewContent = function() {
$scope.winTesting
.refresh({
//url: '../References/View-entry.html'
template: kendo.template($('#tplView').html())
})
.setOptions({
title: "View User Detail"
});
//$scope.$apply(function() {
// $compile($scope.winTesting.element)($scope);
//});
$scope.winTesting.open().center();
}
}
]);
lets assume that the content of Test-entry.html is the same as tplAddNew Template
Now, when i will use the $compile function, it will show an error of $apply already in progress
Any help would be appreciated. TIA
i also prepared a JSFiddle
Kendo has not really refined this widget yet. So in light of that use the $timeout service:
$timeout(function() {
$compile($scope.winTesting.element)($scope);
}, true);
The last boolean parameter does (more or less) a $scope.$apply. See the Documentation
Edit:
There is also some cool stuff you could do with the $parse service as well. You might find it useful as explained in this blog

Multiple Angularjs Applications (Driving Portlets)

I have a use case that requires the loading of separate angular applications.
Based on several stack overflow questions and this google thread, it's doable. However, I can't get it to work.
Looking at the documentation:
http://docs.angularjs.org/api/angular.bootstrap
It looks like you need to provide the element (what is the right way to get a handle on the element?), and then how to tie it back to config, controllers, etc. And how would this work with routes? IE how does collision work, ie app a and app b map /foo to /fooa.html and /foob.html respectively... or each app describes its own .otherwise?
Thanks!
So given the requirement that this be a service driven content the only way I can see to do this is kind of a mix between angular and standard html practices. Effectively you'll want to take a page from the plunker book and use Iframes to contain each individual portlet.
<!doctype html> <html lang="en">
<body ng-app="plunker" ng-controller="MainCtrl">
<!-- define foo -->
<div>
<ul class="menu">
<li>foo1</li>
<li>foo2</li>
</ul>
<iframe seamless="true" ng-src="foo.index.html{{fooRoute}}"></iframe> </div>
<div>
<ul class="menu">
<li>bar1</li>
<li>bar2</li>
</ul>
<iframe seamless="true" ng-src="bar.index.html{{barRoute}}"></iframe> </div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script> <script src="app.js"></script> </body> </html>
Then on each of these portlets you'll want to have a completely separate application (including the loading of resources).
<!doctype html>
<html lang="en">
<body ng-app="fooApp">
<div ng-view></div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script>
<script>
var app = angular.module('fooApp', ['fooApp.controllers']);
// Configure the app
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/foo1', {template: '<h1>Foo</h1><h2>foo1</h2>', controller: 'MyCtrl1'});
$routeProvider.when('/foo2', {template: '<h1>Foo</h1><h2>foo2</h2>', controller: 'MyCtrl2'});
}]);
angular.module('fooApp.controllers', []).
controller('MyCtrl1', [function () {
console.log("fooApp.MyCtrl1 invoked.");
}])
.controller('MyCtrl2', [function () {
console.log("fooApp.MyCtrl2 invoked.");
}]);
</script>
</body>
</html>
This is a little less efficient for loading than utilizing a common application base but at the moment this isn't feasible. There is talk at the angular-ui's ui-router team about controlling independent views which may be a workable solution for you but it is currently not implemented, you can follow the discussion at https://github.com/angular-ui/ui-router/issues/84 and chime in with your need. There is also now an issue specifically for this on the ui-router issues list at https://github.com/angular-ui/ui-router/issues/160.
Working plunker of this design: http://plnkr.co/edit/sPoK3I?p=preview
Ok so I figured out how to do this using the angular ui-router the key comes down to the ability of the angular ui-router to transition states without effecting the URL.
The steps to get this working
First instantiate each application as a stand alone application using
a manual bootstrap to an ID'd element.
Attach the ui-router $stateProvider to each application to drive the internal state transitions (routes).
You must leave off the url key here for each defined state or you'll reset the page by changing the url on each state transition.
Setup a state function in a main controller to drive state changes.
The following is the code to get this working:
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.0.x" src="http://code.angularjs.org/1.0.7/angular.min.js" data-semver="1.0.7"></script>
<script src="angular-ui-states.min.js"></script>
<script src="app.js"></script>
</head>
<!-- define foo -->
<div id="fooApp" ng-controller="MainCtrl">
<ul class="menu">
<li>foo1</li>
<li>foo2</li>
</ul>
<div ui-view>
</div>
</div>
<script>
// Declare app level module which depends on filters, and services
var app = angular.module('fooApp', ['fooApp.controllers', 'ui.state']);
// Configure the app
app.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('foo1',
{
template: '<h1>Foo</h1><h2>foo1</h2>',
controller: 'MyCtrl1'
})
.state('foo2',
{
template: '<h1>Foo</h1><h2>foo2</h2>',
controller: 'MyCtrl2'
});
}]);
angular.module('fooApp.controllers', [])
.controller('MainCtrl', ['$scope', '$state', function($scope, $state){
$scope.state = function(name){
console.log('Transition to state ' + name);
$state.transitionTo(name);
}
}])
.controller('MyCtrl1', [function () {
console.log("fooApp.MyCtrl1 invoked.");
}])
.controller('MyCtrl2', [function () {
console.log("fooApp.MyCtrl2 invoked.");
}]);
// manually bootstrap
var div = document.getElementById('fooApp');
console.log(div);
angular.bootstrap(div, ['fooApp']);
</script>
<!-- define bar -->
<div id="barApp" ng-controller="MainCtrl">
<ul class="menu">
<li>bar1</li>
<li>bar2</li>
</ul>
<div ui-view>
</div>
</div>
<script>
// Declare app level module which depends on filters, and services
var app = angular.module('barApp', ['barApp.controllers', 'ui.state']);
app.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('bar1',
{
template: '<h1>Bar</h1><h2>bar1</h2>',
controller: 'MyCtrl1'
})
.state('bar2',
{
template: '<h1>Bar</h1><h2>bar2</h2>',
controller: 'MyCtrl2'
});
}]);
angular.module('barApp.controllers', [])
.controller('MainCtrl', ['$scope', '$state', function($scope, $state){
$scope.state = function(name){
console.log('Transition to state ' + name);
$state.transitionTo(name);
}
}])
.controller('MyCtrl1', [function () {
console.log("barApp.MyCtrl1 invoked.");
}])
.controller('MyCtrl2', [function () {
console.log("barApp.MyCtrl2 invoked.");
}]);
// manually bootstrap
var div = document.getElementById('barApp');
console.log(div);
angular.bootstrap(div, ['barApp']);
</script>
</body>
</html>
Working plunker of this solution at http://plnkr.co/edit/bXSN8qSMdioZJLYs2zyk?p=preview
Please see my previous answer for a discussion currently occurring to make portlet support more intrinsic in the ui-router.
Figured it out. Here's how to successfully load two angular applications in parallel. Also see that I named the controllers the same for each app to show that dependencies will not collide (since they are scoped within each respective app via module):
<!doctype html>
<html lang="en">
<body>
<script src="lib/angular/angular.js"></script>
<!-- define foo -->
<div id="fooApp">
<ul class="menu">
<li>foo1</li>
<li>foo2</li>
</ul>
<div ng-view>
</div>
</div>
<script>
// Declare app level module which depends on filters, and services
var app = angular.module('fooApp', ['fooApp.controllers']);
// Configure the app
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/foo1', {template: '<h1>Foo</h1><h2>foo1</h2>', controller: 'MyCtrl1'});
$routeProvider.when('/foo2', {template: '<h1>Foo</h1><h2>foo2</h2>', controller: 'MyCtrl2'});
}]);
angular.module('fooApp.controllers', []).
controller('MyCtrl1', [function () {
console.log("fooApp.MyCtrl1 invoked.");
}])
.controller('MyCtrl2', [function () {
console.log("fooApp.MyCtrl2 invoked.");
}]);
// manually bootstrap
var div = document.getElementById('fooApp');
console.log(div);
angular.bootstrap(div, ['fooApp']);
</script>
<!-- define bar -->
<div id="barApp">
<ul class="menu">
<li>bar1</li>
<li>bar2</li>
</ul>
<div ng-view>
</div>
</div>
<script>
// Declare app level module which depends on filters, and services
var app = angular.module('barApp', ['barApp.controllers']);
// Configure the app
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/bar1', {template: '<h1>Bar</h1><h2>bar1</h2>', controller: 'MyCtrl1'});
$routeProvider.when('/bar2', {template: '<h1>Bar</h1><h2>bar2</h2>', controller: 'MyCtrl2'});
}]);
angular.module('barApp.controllers', []).
controller('MyCtrl1', [function () {
console.log("barApp.MyCtrl1 invoked.");
}])
.controller('MyCtrl2', [function () {
console.log("barApp.MyCtrl2 invoked.");
}]);
// manually bootstrap
var div = document.getElementById('barApp');
console.log(div);
angular.bootstrap(div, ['barApp']);
</script>
</body>
</html>
The only remaining question is how to deal with routing collisions.
Well you have 2 choices here:
if you create them as angular.module() there would not be a way atm to connect the modules with each other.
if you create directives with a templateURL to lazyload your components you could broadcast shared attributes and listen to them and you could use the same services in your app.
Probably that would be the best for you.

Categories

Resources