While working on a project in ionic i noticed my two data-binding bugging out.
I really can't get my head around why this is the case.
I tried making a new ionic project with "ionic start myApp sidemenu" to test out the data binding, and even in the new project it is not working. Am i the one doing something wrong or is this just really bugging out?
Link to the working databinding example i'm following
As you can see in that example, when you fill in the input fields: first name, last name AND full name gets update. When i add this code to an ionic project, only the first/last name get updated, but the full name doesn't get updated and stay on the values initialized in the controller.
It look likes the $scope.firstName and $scope.lastName don't get 'live updated' in the controller but only in the view for some reason.
If i try to console log the $scope.firstName after i filled in the input field, it still returns 'john' (the initial value) and not the value i filled in.
Code in ionic:
html
<ion-view view-title="Search">
<ion-content>
<strong>First name:</strong> {{firstName}}<br />
<strong>Last name:</strong> <span ng-bind="lastName"></span><br />
<strong>Full name:</strong> {{getFullName()}}<br />
<br />
<label>Set the first name: <input type="text" ng-model="firstName"/></label><br />
<label>Set the last name: <input type="text" ng-model="lastName"/></label>
</ion-content>
</ion-view>
controller:
angular.module('starter.controllers', [])
.controller('SearchCtrl', function($scope) {
// Initialize the model variables
$scope.firstName = "John";
$scope.lastName = "Doe";
// Define utility functions
$scope.getFullName = function ()
{
return $scope.firstName + " " + $scope.lastName;
};
})
routing:
angular.module('starter', ['ionic', 'starter.controllers'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'templates/menu.html',
controller: 'AppCtrl'
})
.state('app.search', {
url: '/search',
views: {
'menuContent': {
templateUrl: 'templates/search.html',
controller: 'SearchCtrl'
}
}
})
You should use ng-bind. From AngularDocs
The ngBind attribute tells AngularJS to replace the text content of
the specified HTML element with the value of a given expression, and
to update the text content when the value of that expression changes
replace
<strong>Full name:</strong> {{getFullName()}}<br />
with
<strong>Full name:</strong> <span ng-bind="getFullName()"></span><br />
Related
I am retrieving all the data and storing it in a variable "storedata", displaying it in the HTML View "A" which is associated with an angular Controller, I am making use of thymeleaf template and however on click of the ID i want to display the contents in another HTML View "B" for which i want to make use of the variable "storedata" which already has the data. So I tried linking HTML View "B" with the same angular Controller thinking that I could access it directly, however i couldn't. your suggestion would be valuable. all the files are pasted below.
HTML "A"
<div data-ng-repeat="storedata in storeDataModel">
<a class="clickableRow" title="Click to get User details" onclick="window.open('B.html')" >{{storedata.ID}}
</a>
</div>
HTML "B"
<div ng-controller="angularController">
<a> HELLO WORLD..!! {{storedata.ID}}</a>
</div>
You cannot load another view without bootstrapping it. By calling window. open, you are only loading a html file that has nothing to do with the angular application you are working with.
For more info, take a look at angular bootstrapping.
Another approach would be to use ng-route or ui-router. I suggest the latter one.
For example look at below code:
angular.module('app', ['ui.router'])
.config(function($stateProvider, $urlRouterProvider) {
// State definition
$stateProvider
.state('homeState', {
abstract: true,
url: '/home',
template: '<div> {{ title }} ' +
'<div ui-view><div>' +
'</div>',
controller: 'HomeController'
})
.state('homeState.childStateA', {
url: '/stateA',
template: '<div> {{ data }} </div>' +
'<button data-ng-click="$state.go(\'homeState.childStateB\')"> Click Me To GoTo StateB </button>',
controller: 'StateAController'
})
.state('homeState.childStateB', {
url: '/stateB',
template: '<div> {{ data }} </div>' +
'<button data-ng-click="$state.go(\'homeState.childStateA\')"> Click Me To GoTo StateA </button>',
controller: 'StateBController'
});
// Default to stateA
$urlRouterProvider.otherwise('/home/stateA');
})
.run(function($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
})
.controller('HomeController', function($scope) {
// homeState data
$scope.title = 'State example';
})
.controller('StateAController', function($scope) {
// StateA data
$scope.data = 'Hi State A';
})
.controller('StateBController', function($scope) {
// StateB data
$scope.data = 'Hi State B';
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.4.2/angular-ui-router.min.js"></script>
<div data-ng-app="app">
<div ui-view></div>
</div>
So I have the code for a search bar in its own template, which I have in a custom directive. Then I put that directive in the my Navbar template.
<form class="navbar-form navbar-left" role="search">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search" ng-model="searchText">
</div>
<button type="submit" class="btn btn-default" ng-click="go('/searchResults')">Submit</button>
</form>
.
.state('searchResults', {
url: '/searchResults',
templateUrl: 'templates/searchResults.html',
controller: 'searchController'
})
}]).
directive('searchBar', function() {
return {
restrict: 'E',
templateUrl: 'templates/search.html',
controller: "searchController"
}
});
My SearchController handles the scope for this search bar, but I'm having some trouble binding data to another template, which is my searchResults template. My SearchController calls on a service I wrote which retrieves some data and works fine. When I try to bind the data to my SearchResults page however, angular does not bind any of the data received from the service, (it will console log out the correct data though).
Name: {{player.playerName}}<br>
Link: {{player.link}}<br>
Things: {{things}}<br>
controller:
angular
.module('app')
.controller('searchController', ['$scope',"$http","$location", "PlayerDAO", function($scope, $http, $location, PlayerDAO){
$scope.things="stuff";
$scope.go = function ( path ) {
if(checkSearchBar()){
$location.path( path );
PlayerDAO.getPlayers($scope.searchText).then($scope.postPlayerToResultsPage, onError);
}
};
$scope.postPlayerToResultsPage=function(result){
$scope.player=result;
$scope.things="Hooray, it worked";
$scope.player.playerName;
console.log(result);
};
}]);
Oddly enough to me however, it will bind any data that is not in the function I use to get the data (i.e. it will bind {{things}}), but any of the data in my function "postPlayerToResultsPage", isn't seen by Angular. If I take the code for the search bar and put it in my search results page directly, the nav-bar that appears on that page works flawlessly, however I need the search-bar to be on my main navigation template, view-able on all pages.
I suspect your data isn't binding due to the prototypical nature of your directive's $scope.
Try using controllerAs syntax for data binding to avoid $scope ambiguity. e.g.
directive:
controller: 'searchController',
controllerAs: 'searchCtl'
controller:
var controller = this;
$scope.postPlayerToResultsPage=function(result){
controller.player=result;
controller.things="Hooray, it worked";
controller.player.playerName;
console.log(result);
};
html:
Name: {{searchCtl.player.playerName}}<br>
Link: {{searchCtl.player.link}}<br>
Things: {{searchCtl.things}}<br>
Though the states are changing successfully, I can't get the ui-view to update:
HTML
<a ui-sref="promo.foo">Foo state</a>
<a ui-sref="promo.bar">Bar state</a>
<div ui-view=""></div>
JavaScript
$urlRouterProvider.otherwise("/");
$stateProvider
.state('promo', {
url: "/",
abstract: true
})
.state('promo.foo', {
url: "promo/foo",
template: "'<h3>Foo</h3>'",
controller: function($scope) {
$scope.value = 'foo';
}
})
.state('promo.bar', {
url: "promo/bar",
template: "'<h3>Bar</h3>'",
controller: function($scope) {
$scope.value = 'bar';
}
})
Plnkr (with bootstrap styling)
I have also tried setting ui-view to equal specific states also; and to dynamically change its RHS from my $scope.
Since you're trying to create nested views, the home state should have a template with an ui-view-element in it.
Also you have both double and single quotes in the template
template: "'<h3>Foo</h3>'"
Is this Plunker what you had in mind?
Give your abstract state a template containing inside which your sub states will render ... eg http://scotch.io/tutorials/javascript/angular-routing-using-ui-router
I have following three buttons on top of my page with input box underneath it.
<div>
<form>
<div>
Enter Show Name<input type="text" ng-model="showName" />
</div>
</form>
</div>
<div>
<button ng-click="href="/api/renameShow"">Rename Show</button>
<button ng-click="href="/api/updateShow"">Update Show</button>
<button ng-click="href="/api/checkShow"">Check Show</button>
</div>
My module code with routes is
var showApp = angular.module("showApp", ["ngRoute", "ngResource", "ui"]).
config(function ($routeProvider, $locationProvider) {
$routeProvider.
when('/',
{
controller: '',
templateUrl: 'main.html'
}).
when('/api/renameShow', { controller: 'renameShowCtrl', templateUrl: '/templates/renameShow.html' }).
when('/api/updateShow', { controller: 'updateShowCtrl', templateUrl: '/templates/updateShow.html' }).
when('/api/checkShow', { controller: 'checkShowCtrl', templateUrl: '/templates/checkShow.html' });
Basically what I am trying to do is that when one of the buttons is clicked the ng-click calls the corrosponding page passing the parameter "showName" with it.
Please let me know how to fix it. Thanks
First of all you need to tell your destination controllers (the page you are referring to) to expect and accept a parameter when we navigate to that page:
$routeProvider.when('/api/renameShow/:showName?', {
controller: 'renameShowCtrl',
templateUrl: '/templates/renameShow.html'
})
The question mark after the parameter denotes that it's an optional parameter. You can achieve the same with anchor tags:
Go to view 2
If you insist on using buttons, write a custom function hooking onto the ng-click of the button, and then pass whatever parameter you want like this from your current controller:
<button ng-click="customNavigate('Mike')">Rename Show</button>
And in the controller:
$scope.customNavigate=function(msg){
$location.path("/view2"+msg)
}
and then in the destination controller:
app.controller("renameShowCtrl",function($scope,$routeParams){
$scope.showName=$routeParams.showName
});
Say we need psoid in sodtl.htm:
In HTML - so.html:
<tr ng-controller="SoController" ng-repeat="x in sos">
<td>{{x.date}}</td>
<td>Dtl</td>
</tr>
In AngularJs - app.js - Config:
app.config(function ($routeProvider)
{
$routeProvider.
when ('/sodtl/:psoid?',
{
templateUrl : 'pages/sodtl.html',
controller : 'SoDtlController'
}
)
});
In Controller - app.js:
app.controller('SoDtlController', function ($scope, $http, $location, $routeParams) {
$scope.message = " $routeParams.psoid = " + $routeParams.psoid;
});
Thus you can use psoid in showing data in sodtl.html page.
I'm reading a book on AngularJS and There's something that confuses me
There are two Controllers
EditCtrl
app.controller('EditCtrl', ['$scope', '$location', 'recipe',
function($scope, $location, recipe){
$scope.recipe = recipe;
$scope.save = function(){
$scope.recipe.$save(function(recipe){
$location.path('/view/', + recipe.id);
});
};
$scope.remove = function(){
delete $scope.recipe;
$location.path("/");
};
}]);
IngredientsCtrl
app.controller('IngredientsCtrl', ['$scope',
function($scope){
$scope.addIngredients = function(){
var ingredients = $scope.recipe.ingredients;
ingredients[ingredients.length] = {};
};
$scope.removeIngredient = function(index) {
$scope.recipe.ingredients.slice(index, 1);
};
}]);
What I don't understand is how the IngredientsCtrl is a child of EditCtrl. I can't see the relation. The book clearly states this case, and I'm sure it's the case because the example app works fine, but I need help understanding what it is that makes IngredientsCtrl a child of EditCtrl. Doesn't makes sense to me.
Edit: With relevent HTML
<div class="control-group">
<label class="control-label" for="ingredients">Ingredients:</label>
<div class="controls">
<ul id="ingredients" class="unstyled" ng-controller="IngredientsCtrl">
<li ng-repeat="ingredient in recipe.ingredients">
<input ng-model="ingredient.amount" class="input-mini">
<input ng-model="ingredient.amountUnits" class="input-small">
<input ng-model="ingredient.ingredientName">
<button type="button" class="btn btn-mini" ng-click="removeIngredient($index)"><i class="icon-minus-sign"></i> Delete </button>
</li>
<button type="button" class="btn btn-mini" ng-click="addIngredient()"><i class="icon-plus-sign"></i> Add </button>
</ul>
</div>
Edit: Snippet from book
All the other controllers that we saw so far are linked to particular views on the UI. But
the Ingredients Controller is special. It’s a child controller that is used on the edit pages
to encapsulate certain functionality that is not needed at the higher level. The interesting thing to note is that since it is a child controller, it inherits the scope from the parent
controller (the Edit/New controllers in this case). Thus, it has access to the
$scope.recipe from the parent.
Edit: with routing
var app = angular.module('guthub',
['guthub.directives', 'guthub.services']);
app.config(['$routeProvider',
function($routeProvider){
$routeProvider.
when('/', {
controller: 'ListCtrl',
resolve: {
recipes: function(MultipleRecipeLoader){
return MultipleRecipeLoader();
}
},
templateUrl: '/view/list.html'
}).
when('/edit/:recipeId', {
controller: 'EditCtrl',
resolve: {
recipe: function(RecipeLoader) {
return RecipeLoader();
}
},
templateUrl: '/view/recipeForm.html'
}).
when('/view/:recipeId', {
controller: 'ViewCtrl',
resolve: {
recipe: function(RecipeLoader) {
return RecipeLoader();
}
},
templateUrl: '/view/viewRecipe.html'
}).
when('/new', {
controller: 'NewCtrl',
templateUrl: '/view/recipeForm.html'
}).
otherwise({redirectTo: '/'});
}]);
Two controllers share a Parent-Child relationship if you place the ng-controller directive on two nested html elements.
If you take a look at your HTML template, you should see something like this:
<!-- parent controller -->
<div ng-controller="EditCtrl">
<!-- child controller -->
<div ng-controller="IngredientsCtrl"></div>
</div>
There is no such thing in angular as a child controller. However, you can place a controller inside of another in the dom.
<div ng-controller="EditCtrl">
<div ng-controller="IngredientsCtrl">
// Here you have access to the scope of both controllers
</div>
</div>
The answer to your question "What makes these two controllers related?" is "nothing". They can be nested as I described, but so could any two controllers be.
Both controllers in your example read from the scope. This is bad practice as stated by Miško Hevery himself (http://www.youtube.com/watch?v=ZhfUv0spHCY).
Paraphrasing:
Inside of a controller you shoul only do write-operations to the scope and in the templates you should do read only
Based on these code snippets. I would not recommend the book you read for learning angularjs.