Angular JS $scope query - javascript

I'm trying to do the following:
Type something in a search box, perform the related search and show the result defined in a separate view template.
The search thingy is part of a page header and so, my index page is as follows:
index.html
<div class="row search-box">
<div class="col-md-2"></div>
<div class="col-md-6">
<form id="myForm" class="form-inline form-search"
style="padding-left: 10px">
<!-- Search box -->
<input id="in" type="text" ng-model="searchTerm" placeholder="Search for products, categories or brands"
class="search-query input-search">
<button class="btn searchBtn" ng-click="doSearch()" ng-controller="MediaListController">
<i class="icon-search"></i>Search
</button>
</form>
</div>
<div class="col-md-3">
<div class="btn btn-blue cart-btn-cont">
<span class="cart-icon"></span>
</div>
</div>
</div>
...
<div ng-view></div>
Controller (relevant function)
$scope.doSearch = function () {
var type = $scope.mediaType;
$scope.foundItems = MediaService.search().length;
console.log("Found items :"+ $scope.foundItems + "for search term :"+ $scope.searchTerm);
$location.path("/search");
}
app.js
var app= angular.module('sampleApp', ['ngRoute','ngResource','mgcrea.ngStrap']);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/login', {templateUrl: 'app/views/partials/login.html', controller: 'LoginController'});
$routeProvider.when('/search', {templateUrl : 'app/views/partials/tpl/search_result.tpl.html'});
$routeProvider.when('/', {templateUrl: 'app/views/landing_page.html', controller: 'MediaListController'});
$routeProvider.otherwise({redirectTo: '/'});
}]);
Search result template:
Found {{ foundItems }} product(s) for search phrase <i>"{{searchTerm}}"</i>
It all works fine, but in getting to this stage, I am confused by the following:
a. Why is $scope.foundItems not visible in the template i.e, {{foundItems}} works only when I use $scope.$parent.foundItems in the controller?
b. If a new child scope is being created, how come $scope.searchTerm is available in the view template i.e., {{searchTerm}}? Is it because ng-model="searchTerm" creates a model binding in the rootScope?
c. I also saw that {{foundItems}} in the template worked fine if I used $rootScope.foundItems, but what if I want to avoid $rootScope - is the use of $scope.$parent valid?
Thanks in advance.

a. Why is $scope.foundItems not visible in the template i.e, {{foundItems}} works only when I use $scope.$parent.foundItems in the controller?
I think it's a little strange to assign the same controller in the ng-view and then another tag like button. Because button will create its own scope right there. And then ng-view also creates one.
b. If a new child scope is being created, how come $scope.searchTerm is available in the view template i.e., {{searchTerm}}? Is it because ng-model="searchTerm" creates a model binding in the rootScope?
that scope has nothing to do with the doSearch scope actually.
c. I also saw that {{foundItems}} in the template worked fine if I used $rootScope.foundItems, but what if I want to avoid $rootScope - is the use of $scope.$parent valid?
You should probably have a main controller for the page and then call everything from there perhaps.

Related

AngularJS array not updating when using ng-view

I am learning how to use ngRoute to split my html forms into separate views. When I add data to the main array in the index.html the array updates correctly, but when I try the same approach in the html forms that are added in through the ng-view, the array does not render correctly. I can debug and see that the array is getting the new name added, but it will not render on the html.
Index.html
<h1> Names </h1>
<ul ng-repeat="name in names">
<li>{{name.fname}}</li>
</ul>
<h1>Add name in index.html</h1>
<input type="text" ng-model="name" />
<button ng-click="addName(name)">add name</button>
<ul>
<li> First</li>
<li> Second</li>
</ul>
<div class="container">
<div ng-view></div>
</div>
Apps.js
var myApp = angular.module('myApp', ['ngRoute']);
myApp.config(function ($routeProvider) {
$routeProvider
.when('/first', {
templateUrl: 'pages/first.html',
controller: 'mainController'
})
.when('/second', {
templateUrl: 'pages/second.html',
controller: 'mainController'
})
});
myApp.controller('mainController', ['$scope', '$log', function($scope, $log) {
$scope.names = [{fname:'john',lname:'doe'},{fname:'jane',lname:'doe'}];
$scope.addName = function(name){
$scope.names.push({fname:name,lname:'no last name'});
}
}]);
first and second.html are identical
<h1>Add name in first.html</h1>
<input type="text" ng-model="name" />
<button ng-click="addName(name)">add name</button>
This is by design.
The $scope is limited to the scope of the controller, which is everything that is rendered inside the ng-view. This means there are two collections named names, one on the app scope, and one on the controller scope. When you modify the names collection inside the controller, it only modifies this collection, not the one referenced in the root level of the app. (I am assuming that you bind mainController to the body tag, otherwise the addName() in index.html wouldn't work. This by itself is not a great choice, you should not put another controller instance into itself, unless you absolutely know what you are doing.)
The proper way to handle this situation is to put the names collection and the addName() function into a service that you inject into your controllers.

How to use $scope values from Angular included files

In Angularjs using ng-include im facing some trouble...
Im having a single html form and including other html within it.
If this is my main.html..
<div ng-controller="appCtrl">
<div ng-include src="'/Tab1.html'"></div>
{{data.name}}
<!--trying to use one of the Tab1 field but unable to fetch -->
<button type="submit" ng-click=save()>Save</button>
</div>
in Tab1.html
<div ng-controller="appCtrl">
<input type="text" ng-model="data.name">
{{data.name}}<!--getting the value here-->
</div>
in my controller
angular.module('app')
.controller('appCtrl', ['$scope', '$http','$routeParams','$rootScope' ,'$location',
function($scope, $http, $routeParams, $rootScope ,$location){
$scope.save= function(){
console.log($scope.data);//undefined...
}
})
Must be minior mistake but not known where...Thanks in advance for fixing!!
ng-include creates a child scope to acces the parent scope use $prarent
in Tab1.html
<div>
<input type="text" ng-model="$parent.data.name">
{{$parent.data.name}}<!--getting the value here-->
</div>
Do like this
<div>
<input type="text" ng-model="data.name">
{{data.name}}<!--getting the value here-->
</div>
Remove controller in child div and it will take current scope;
also in controller use
$scope.data={name:""};
$scope.save= function(){
console.log($scope.data);
}
and it will work;

AngularJS table data not updating when uib-pagination is wrapped in another directive?

I generated my project using JHipster and one of my entities uses pagination (). Everything is working fine, however I want to include a page size option along with pagination. But I don't see any option for that in UI Bootstrap documentation. Therefore I wrapped the uib-pagination directive in a custom directive.
Here is the directive:
'use strict';
//angularJS directive for Spring Pagination with page size control.
angular.module('myApp')
.directive('springPagination', function(){
return{
restrict: 'AE',
replace: true,
scope: true,
templateUrl: 'scripts/components/pagination/spring-pagination.html',
controller: 'my_entity_controller'
};
})
Here is the template (HTML):
<div class="row row-sm-height" id="pagination_div">
<div class="col-md-6 pagination_panel col-xs-12" id="pagination_left">
<uib-pagination class="pagination-md" total-items="totalItems"
ng-model="page" ng-change="loadAll()" rotate="false"
boundary-links="true" boundary-link-numbers="true" max-size="7"></uib-pagination>
</div>
<div class="col-md-6 pagination_panel col-xs-12" id="pagination_right">
<div class="row pagination_panel_row">
<div class="col-xs-4 pagination_panel_item">
<label>Items Per Page:</label>
</div>
<div class="col-xs-4 pagination_panel_item">
<input class="form-control" placeholder="Items per Page"
type="number" min="5" max="100" ng-model="newItemPerPage"></input>
</div>
<div class="col-xs-4 pagination_panel_item">
<button type="button" class="btn btn-info"
ng-click="setItemPerPage()">Set</button>
</div>
</div>
</div>
</div>
When i click on the item on my custom directive, for example the page number or set page size to 50, AngularJS is able to get the new value and send a REST request to the server and the server response with new data. However, my table remains the same page without any changes.
Can someone give me some directions please? Why is my data not updating like it supposed to without the custom directive? Perhaps there is a build-in option for ui.bootstrap.pagination to display page size so that I don't need to create a custom directive so that there is less hassle??
Silly me. Turns out my approach is doable, but I just forgot to use apostrophe on the boolean. So basically:
scope: true
should be:
scope: 'true'
I am pretty sure I saw other tutorials which use
scope: true
without the apostrophe too. But oh well, at least my problem is solved...
also, there is no need to put controller and replace option (well, at least for my use case i don't need to) because I want my directive to share the same controller from the html that I applied this custom directive to.

How would I create something similar like this in AngularJS

Having a hard time grasping AngularJs.. How would you build something like this simple textfields and animations in AngularJS? I had been looking into using directives but it just isn't adding up to me much. I had been trying to base this from what I learned online but was not having much luck
http://codepen.io/yusufbkr/pen/RPBQqg
HTML:
<div class="materialContainer">
<div class="title">LOGIN</div>
<div class="input">
<label for="name">Username</label>
<input type="text" name="name" id="name">
<span class="spin"></span>
</div>
<div class="input">
<label for="pass">Password</label>
<input type="password" name="pass" id="pass">
<span class="spin"></span>
</div>
<div class="button login">
<button><span>GO</span> <i class="fa fa-check"></i></button>
</div>
Forgot your password?
<div class="title">REGISTER</div>
<div class="input">
<label for="regname">Username</label>
<input type="text" name="regname" id="regname">
<span class="spin"></span>
</div>
<div class="input">
<label for="regpass">Password</label>
<input type="password" name="regpass" id="regpass">
<span class="spin"></span>
</div>
<div class="input">
<label for="reregpass">Repeat Password</label>
<input type="password" name="reregpass" id="reregpass">
<span class="spin"></span>
</div>
<div class="button">
<button><span>NEXT</span></button>
</div>
just use the codepen link ( http://codepen.io/yusufbkr/pen/RPBQqg ), stackoverflow won't let me input the rest of the code...
Thanks! Any help would be incredible
I'm just learning Angular myself. From what I know, you're on the right track to be thinking of directives for swapping out interactive parts of the DOM. I suspect you'll also be needing ui-router for dealing with the widget outcomes (I hear it's the industry standard, vs the built-in ngRouter).
I'm partly writing this out to make sure I understand it, so I hope other, more knowledgeable people will come by and answer any questions you have about it (or point out where I'm misundertanding something.)
So you bring the webpage into the Angular world by, for instance, making the <html></html> tags into <html ng-app="yourApp"></html>. The unchanging html that will be the same on every view is in the index.html file. Put the html for the boxes is in another html file, say box.html. On the index.html file in the place where you want to have your boxes appear, put <div ui-view></div>. The ui-view connects to ui-router. Down at the bottom of the index.html right before closing the body tag, put
<script src="lib/angular/angular.js"></script>
<script src="lib/angular-ui-router/release/angular-ui-router.js"></script>
<script src="app/app.js"></script>.
In app.js, you put something like,
angular.module('yourApp', [
'yourApp.box',
'ui.router'
])
.config(function($stateProvider, $urlRouterProvider, $httpProvider) {
$urlRouterProvider
.otherwise('/signin/child');
$stateProvider
.state('box', {
url: '/signin',
templateUrl: 'app/box/box.html',
controller: 'BoxController'
})
.state('box.child', {
url: '/child',
template: '<span>{{ definedProperty }}</span>'
});
})
});
Starting at the top, you name angular, call its module function, and give it the parameters ('theNameYouChose', ['dependencies','required'])
In the config bit there, you're telling it about dependencies config needs. $stateProvider and $urlRouterProvider are ui-router things, and $httpProvider is, I believe, an angular thing that is still necessary.
In the urlRouterProvider, you're providing the default address the website goes to: in this case it happens to be a template within a template, /signin from the signin state, and /child from the specifics pasted into signin
In the states, you are giving names and properties to the URLs that will be part of your app: like, if someone goes to index.html/signin, the 'signin' state is summoned.
The template within a template might be how you'd get the box variability that you're looking for. In box.html you will have another <div ui-view></div> and that's where the varying thing described in 'signin.child' gets put in.
box.html is also the place you put your specially created html tags, the ones you will make with the directive. I'll talk through those below.
The parent template, 'signin', talks about BoxController. Let's say you built that in box.js. It would look like this:
angular.module('yourApp.box', [])
.controller('BoxController', function ($scope) {
$scope.definedProperty = 'reRegPass',
$scope.arrayOfObjects = [{prop: 'red'},{prop: 'blue'}]
})
.directive('specificBox', function(){
return {
restrict: 'EA',
templateUrl: 'app/box/box-guts.html',
replace: true,
scope: {
source: '='
},
link: function(scope, element, attribute) {
element.on('click', function() {
alert('Functionality in specificBox is working');
}
}
}
});
The first line is again summoning angular module, and then naming it: note we already listed this, 'yourApp.box', as a requirement in app.js. Then we have the controller-naming function, and the appearance of specific properties in their $scope.
The directive is taking the more useful of the two forms a directive can take. They can either return functions (with signatures like the one in .link), or they can return objects that describe new HTML entities. This one is named specificBox, which Angular will translate into <specific-box></specific-box>. This object (technically called a 'directive definition object') can be translated into HTML tags because of the restrict property... 'E' is for element. 'A' is for attribute. I don't know how something that can be an element could also be an attribute, but having both options works, so I'm going with it. (Maybe for your various signin boxes you want a directive that has just 'A' to make new types of attributes.)
You put these specifically-crafted tags into box.html, and everything in box-guts.html will be between those tags... In fact, replacing those tags because of the replace: true.
The .link property is where you would put a function that would do something interesting to that element; turn it red if clicked, whatever. I have an alert example. Uses jQuery Lite for events.
The .scope property is odd. I believe if left off, the specific-box stuff would have the same controller as box (ie, BoxController), with box's scope and dependencies. But here, instead, we're making an isolate scope. box-guts will not depend on anything or have access to anything built before. How will it get interesting changeable data, then..? Every property in the scope object becomes an attribute on specific-box.
The '=' means that you will pass it objects from somewhere, and they will have 2-way data binding (changes made in box-guts will be reflected in the object collection in your app). Other options are '#', one-way data binding, which means you're passing box-guts a string or something that, if it changes in the DOM, you don't care to reflect in your app; or '&' to give it a function from a controller somewhere else in your app.
So ultimately, in box.html, you will have something like
<div class="box-holder">
<div ui-view></div>
<specific-box source="thing" ng-repeat="thing in arrayOfObjects"></specific-box>
</div>
Like I said above, ask questions and maybe we can sort this out.

How to hide show in Angular

I am beginner in angular js
HTML
<div ng-app="myapp">
<div ng-controller="maincontrol">
<div ng-show="!vis">show</div>
<div ng-show="vis">hide</div>
</div>
<div ng-view></div>
</div>
JS
var app = angular.module('myapp', ['ngRoute'])
app.controller('maincontrol', function ($scope) {
$scope.vis = true;
$scope.fun = function () {
if ($scope.user == "home" && $scope.pass == "home") {
console.log($scope.user, $scope.pass);
$scope.vis = false;
}
}
})
app.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'home.html'
})
.when('/contact', {
templateUrl: 'contact.html'
})
});
and also i have two html pages like
home.html
<div ng-controller="maincontrol">
<input ng-model="user"/>
<input ng-model="pass"/>
<div ng-click="fun()">
click
</div>
</div>
contact.html
<div>
contact
</div>
my expectation is after entering home into user and pass. if i click 'click' i need to show 'show' label instead of 'hide'. pls help me.
Each controller has its own scope, when you wrote $scope.vis=false on fun(), you actually created a new variable on maincontroler1 scope. If you expected this variable to affect the view which is binded to maincontroler scope, it won't happen.
I suggest 2 options:
You can use one controller for entire app (If you use same controller in two tags it will still create a new scope although it is the same controller), this way the fun() method that was called from the first view will change the boolean in the single controller and will affect the second view. Please note when you use ng-view you will have to get the variable from the parent.
So I used this code:
$parent.user
$parent.pass
Create this working plunker for you.
Share the vis boolean between 2 controllers using a service. You can
use this post for this option.
You can also use reach parent controller scope from child controller, that can be done if ng-view will be nested in the outer controller. You can use this post for option 3.

Categories