AngularJS ui-router re-render - angularjs

I using ui-router to render a view. After render, how to re-render the view after perform some activity in the view (example return data after searching).
My problem is after render the View, I click a search button to search some records from database. But I don't know how to render the View again. Anything that I need to do in the View's search button?
Hope can give some example to me on how to solve it. Thank you.
var myApp = angular.module('myApp', ['ui.router']);
myApp .config(function($urlRouterProvider, $stateProvider){
$stateProvider
.state('home', {
url: '/',
templateUrl: 'home/Main'
})
})
<div class="col-sm-9">
<div ui-view></div> //render menu content
</div>
Above is Menu Layout
<input id="txtsearch" class="form-control" placeholder="Search member ID or email" />
<input type="submit" id="btnsearch" value="Search" />
Above is View

Related

How to get the uib-popover to open or close when the focus of the input field changes

I have a input field that has the uib-popover control on it. I have followed the documentation on how to get the directive to open but I have noticed some discrepancies in the documentation as well as examples on plnker and SO questions here.
Within my hmtl I have the inputs set as follows:
<div class="form-group col-xs-6 col-sm-6 col-md-6 col-lg-6">
<label>Password</label><input type="{{user.inputType}}" ng-blur="user.validatePassword(user.newUser.password, user.newUser.confirmPassword)" placeholder="Enter Password" id="password" required class="form-control" ng-model="user.newUser.password" uib-popover-template="'myPopoverTemplate.html'" uib-popover-trigger="'focus'"/>
</div>
<div class="form-group col-xs-6 col-sm-6 col-md-6 col-lg-6">
<label>Confirm Password</label>
<input type="{{user.inputType}}" ng-keyup="user.validatePassword(user.newUser.password, user.newUser.confirmPassword)" placeholder="Confirm Password" id="confirmPassword" required class="form-control" ng-model="user.newUser.confirmPassword"/>
<span style="color: red">{{user.message}}</span>
</div>
Most examples as well as the SO questions on here are using an older library as attributes are not prefaced with uib-*.
This code/directive currently works and renders but it only work or appears when clicking in the field and then clicking in the same field to close the popover. I have tried both the focus trigger and the oustsideClick trigger. Both have the same result of not rendering or closing the popover unless clicking in the field.
versions of the frameworks used are:
angularjs 1.5.8
ui-bootstrap 1.3.3
Changing the trigger to match earlier examples were popover-trigger is used vs. uib-popover-trigger is used disables the popover
I have created a working plunker that demonstrates what is happening.
Any suggestions on what I am missing or what I need to change.
Thanks in advance
According to tooltip.js description, in order to set a custom trigger,
it needs to be specified via trigger option passed to the $tooltipProvider.options method. In your case for focus trigger it will be:
app.config(['$uibTooltipProvider', function ($uibTooltipProvider) {
$uibTooltipProvider.options({ trigger: 'focus' });
}]);
Updated plunker that shows how to trigger tooltip on focus handler.
There's a problem of your code, please modify like below:
app.js:
(function() {
var app = angular.module('app', ['ui.bootstrap']);
app.controller('main',[ '$scope', main]);
function main($scope)
{
vm = this;
vm.message = 'hello';
vm.dynamicPopover = {
content: 'Hello, World!',
templateUrl: 'myPopoverTemplate.html',
title: 'Title'
};
}
}());
index.html
<input class="form-control" uib-popover-template="vm.dynamicPopover.templateUrl" popover-trigger="focus"/>
Actually, you can not just pass the template's id to the uib-popover-template attribute, you need to create an object to map it waited to pass.

How to pass an array from one view to another within same controller

I am just a newbie to angularjs. I have a form in one view of my application which shows on my other view. There is only one controller for the application. The user can enter the fields in the form which should get displayed on the other view.
The code looks like this.
var app2 = angular.module('myApp2', ['ngRoute','ngStorage']);
app2.controller('rtCtrl', function($scope,$localStorage,$rootScope){
$scope.names = [
{name:'Jani',email:'jani#gmail.com'},
{name:'Hege',email:'hege#gmail.com'},
{name:'Kai',email:'kai#gmail.com'}
];
$rootScope.namesfinal = $scope.names;
$scope.saveData = function(){
$scope.names.push({name: $scope.username, email: $scope.emailaddress});
$localStorage.localData = $scope.names;
$rootScope.namesfinal = $localStorage.localData;
console.log($rootScope.namesfinal);
};
}
);
app2.config(['$routeProvider',function($routeProvider) {
$routeProvider.when('/page2', {
templateUrl: 'Home2.html',
controller: 'rtCtrl'
}).when('/page3', {
templateUrl: 'Home3.html',
controller: 'rtCtrl'
}).otherwise({
redirectTo: '/'
});
}]);
<div ng-app="myApp2" ng-controller="rtCtrl">
<!--a href="#page2">CLick here for page 2</a-->
<button ng-click="traverse()">Page2</button><br>
CLick here for page 3
<div ng-view></div>
</div>
//The second page comes here
<div>This is the second page<br>
<!--<button ng-click="locstor()">Click Here</button>-->
<span ng-repeat="x in namesfinal">
Name: <span ng-bind="x.name"></span> Email: <span ng-bind="x.email"></span><br>
</span>
</div>
//the form page comes here
<div>This is the third page
<form name="form1" novalidate>
Name: <input type="text" name="username" ng-model="username" required>
<span ng-show="form1.username.$pristine">Enter email here.</span>
<span style="color:red;" ng-show="form1.username.$dirty && form1.username.$invalid && form1.username.$error.required">
User name cannot be left empty.</span><br>
Email: <input type="email" name="emailaddress" ng-model="emailaddress" required>
<span style="color:red;" ng-show="form1.emailaddress.$error.email">Email is not valid.</span><br>
<!-- Password: <input type="password" ng-model="userpassword" required><span ng-show="">Password should be at least 8 characters long</span>-->
<input type="submit" value="Submit" ng-disabled="form1.username.$pristine || form1.emailaddress.$pristine || form1.username.$dirty && form1.username.$invalid || form1.emailaddress.$dirty && form1.emailaddress.$invalid"
ng-click="saveData()">
</form>
</div>
Can you tell me why is the array not getting updated on the view of the second page after clicking on the submit button.
Need to understand that although you are using the same controller ... each view will run a new instance of that controller and the scope from previous path (controller) is destroyed once view changes.
You need to use a service to share data across the application
You have two "instances" of your controller, one for each view. If you wan't to share data between those you can use services/factories. Angular guarantees that only one instance will exist of a given service during the app's lifecycle and this makes it an ideal place to share data.
Other approach is to use the rootScope. It looks easier but this solution can easily lead to a polluted rootScope. In general it is better to separate your code so it will be easier to write nice unit tests and maintain the code.
You use 1 controller for two separate pages. The problem is - when you go to another page your current controller will be destroyed and that next page's controller will be created. This will happen even if you use 1 controller function for 2 different pages. You can see it if you place debugger in your controller code. So you can't use controller to save state when moving to another page.
You can use factory for this. factories (and services and providers) are singletons in angular. So they won't be recreated when you go to another page.
tl;dr : create a factory to save your data when you move to another page

Angularjs Show logout button, when I click in SignIn button

I have an login form in a specific partial (that is presented in the body of the main page).
login.html
<form name="loginForm" class="form-horizontal" ng-controller="loginController" ng-submit="submit()" novalidate>
<div class="input-group" >
<input type="text" class="form-control" name="username" ng-model="username" >
</div>
<div class="input-group" >
<input type="password" class="form-control" name="password" ng-model="password" >
</div>
<div style="margin-top:10px" class="form-group">
<!-- Button -->
<div class="col-sm-12 controls">
<button type="submit" class="btn btn-info"><i class="icon-hand-right"></i>Log In</button>
</div>
</div>
</form>
So, when i click in Login button, I need to show a logout button. this is on the main page along with the menu.
How do I get it? I've tried using the ng-show without success
index.html
<button type="submit" ng-show="showBtn" ng-controller="loginController" ng-click="logOut()">Sign out</button>
controller.js
controller('logincontroller', function($scope) {
$scope.showBtn= false;
$scope.loginForm = function() {
$scope.showBtn= true;
}
}).
Every time you use the 'ng-controller' attribute, it creates a new instance of the controller, so your login form does not share the same scope as your logout button.
Move the controller attribute higher up in the DOM so it covers the form and the button and update the logout button's ng-show to:
<button type="submit" ng-show="loggedIn" ng-controller="loginController" ng-click="logOut()">Sign out</button>
then the button will only show when $scope.loggedIn is true in your shared loginController.
I would suggest you should have a base controller such as dashboardCtrl or mainAppCtrl the first controller that loads up after the config phase of the application.
This single controller should handle all the logic for your login and logout code.
You are calling loginController twice from index.html and logic.html(in your main controller) which in my opinion is not that good a practice.
You should initialize the main controller showing the login div(form) and after the user logs in. Call $scope.loginForm() function you should set a flag in your case $scope.loggedIn to true.
As this is a single controller you have a common $scope which has binding with values in views and controller so using a ng-show should work.
Calling of controllers on divs like you are doing for task which need to use a common scope should be avoided.
Edit:-
You can use ng-route or ui-router(much better) providers at config time to create routes that handle the task for routing.
With ui-router code for routing looks like this.
myApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/state1");
$stateProvider
.state('state1', {
url: "/state1",
templateUrl: "partials/state1.html"
})
});
ui-router has many configuration options check it out in docs.
Similarly you can look for code for ng-router code in angular docs.

Angular JS - Change path, Same controller, don't reload scope

I know it's been asked so many times here and I found it too. But it could not solve my problem.
Here is the case. I have one AngularJS application.
I have a list page. I have a button to add. When I click on add button, a pop-up window will come with a form. I want to change the URL when the pop-up comes but in the same controller.
Also I would like to add some other buttons on each, some html display as popup-or other location, but same controller without reloading all scope when url changes.
What I have tried.
app.js
var WebClientApp = angular.module('WebClientApp', [
'ngCookies',
'ngResource',
'ngSanitize',
'ui.bootstrap',
'ngRoute'
]);
WebClientApp.config(function ($routeProvider) {
$routeProvider
.when('/groups/:template', {
templateUrl: 'groups.html',
controller: 'GroupCtrl'
}
groups.html
<div>
<button ng-click="showAdd()">Add Group</button>
<div ng-include src="views/listpage.html">
<div ng-if="addGroupModal" class="popup-modal">
<form name="addGroup" ng-submit="addandEditGroup()">
<input type="text" ng-model="group.name">
</form>
<div>
<div ng-if="editGroupModal" class="popup-modal">
<form name="editGroup" ng-submit="saveGroup()">
<input type="text" ng-model="group.name">
<input type="text" ng-model="group.desc">
<input type="text" ng-model="group.id">
</form>
<div>
Controllers.js
WebClientApp.controller('GroupCtrl', function ($scope,$http, $location, $routeParams) {
$scope.group = {};
$scope.showAdd=function(){
$location.path('/groups/add');
}
var template = $routeParams.template;
switch(template){
case 'add':
loadAddPage();
break;
case 'edit':
loadEditPage();
break;
default:
loadListPageHideAll();
break;
}
function loadAddPage() {
$scope.addGroupModal=true;
$scope.editGroupModal=false;
}
function loadEditPage(){
$scope.addGroupModal=false;
$scope.editGroupModal=true;
}
function loadListPageHideAll() {
$scope.addGroupModal=false;
$scope.editGroupModal=false;
// connect to server and list all groups
}
$scope.addandEditGroup = function() {
$location.path('/groups/edit');
}
$scope.saveGroup = function() {
// Save group with $scope.group.
$location.path('/groups');
}
});
When I click on add button, it will show the add form. When I enter group name, and submit, it should show edit form after changing url with the group name filled in the form. But when I try, the value of group object becomes empty since the url is changing. I added the following in controller, but don't know what to do exactly after.
$scope.$on('$routeChangeStart', function(event, present, last) {
console.log(event,present,last);
});
How to assign the scope variables of last route to present route scope. I tried reload on search to false also, But it didnt work.
There might be an error here :
function loadEditPage(){
$scope.addGroupModal=false;
$scope.editGroupModal=true;
}
There are probably some typos in the HTML template code you posted, but what you are basically doing is hiding the parent addGroupModal and showing the child editGroupModal. Remove the nesting and the tags like this:
<div ng-if="addGroupModal" class="popup-modal">
<form name="addGroup" ng-submit="addandEditGroup()">
<input type="text" ng-model="group.name">
</form>
</div>
<div>
<div ng-if="editGroupModal" class="popup-modal">
<form name="editGroup" ng-submit="saveGroup()">
<input type="text" ng-model="group.name">
<input type="text" ng-model="group.desc">
<input type="text" ng-model="group.id">
</form>
</div>
</div>
Here is the plunkr ( hit enter to submit the form): http://plnkr.co/edit/MGT8HZ4lpgVWCkWlt8Ak?p=preview
If this is what you want to acheive, honestly you are complicating things ... There are simpler solutions.
I see! What you want to acheive is to have a reference of the old group variable before the route was changed... And you want to do that using the same controller...
Ok, to get the group from the last controller, you are half way there . You have to store the group somewhere because the targetScopes and currentScopes you receive in the $routeChange listeners don't point to the scopes.
http://plnkr.co/edit/HfK3fhVtZ4bxHtpiFR3B?p=preview
$scope.group = $rootScope.group || {};
$scope.$on('$routeChangeStart', function(event, present, last) {
console.log('start change route');
$rootScope.group = event.currentScope.group;
console.log('target scope group ',event.currentScope.group);
});
I agree the rootScope might not be the best place to keep that variable, but you can also put it inside an angular constant of variable.

From AngularJS how to pass data from a controller+template to another controller+template?

I'm building an application with AngularJS and Slim PHP framework for the backend, now I completed my 1st form and created a route to the template for it. Now my problem arise when I want to pass my data to another controller, I need to pass the data to another controller+view(template), I don't want to pollute my first view neither the controller of it and so I really want/need to pass the data to another controller which I could play with my data and another form (the 2nd form is for calculation and other stuff)...So you can call the first controller a pre-save, while the real data save (backend to DB) will only happen in the second controller+template. Here is a short of my 1st template view that has the form:
<form novalidate id="formAdd" name="formAdd" class="form-horizontal well col-md-7 col-md-pull-5" method="post">
<fieldset>
<legend>Transaction form</legend>
<div class="form-group">
<label for="symbol" class="col-sm-4 control-label">Symbol</label>
<div class="col-sm-5 symbols">
<input type="text" name="symbol" class="form-control" ng-model="trsn.symbol" placeholder="symbol" required />
</div>
</div>
<div class="form-group">
<label for="accnt_id" class="col-sm-4 control-label">Account</label>
<div class="col-sm-5">
<select id="accnt_id" name="accnt_id" ng-model="trsn.accnt_id" class="form-control" required>
<option value="">...</option>
<option ng-repeat="account in trsn.accounts" value="{{account.accnt_id}}">{{account.accnt_name}}</option>
</select>
</div>
</div>
<!-- ....etc, etc.... -->
<div class="form-actions col-sm-8 col-sm-offset-4">
<button type="submit" name="save_btn" class="btn btn-primary" ng-disabled="formAdd.$invalid" ng-click="preSaveTrsn(trsn, formAdd)">Save transaction</button>
<button type="reset" class="btn btn-default">Cancel</button>
</div>
</fieldset>
</form>
then the app with the module and routes:
var investingApp = angular.module('investingApp', ['ngSanitize','ngResource', 'ngRoute'])
.config(function($routeProvider, $locationProvider) {
$routeProvider.when('/new-trsn',
{
templateUrl: 'templates/StockTransaction.html',
controller: 'StockTransactionController'
});
$routeProvider.when('/presave-trsn',
{
templateUrl: 'templates/PreSaveTransaction.html',
controller: 'PreSaveTrsnController'
});
});
now inside my first controller is the presave function, which is empty since I don't know what to do with it so that I can send the transaction data to the next controller+view:
investingApp.controller('StockTransactionController',
function TransactionController($scope, $http, $location, $compile, $timeout, transactionDataService, dateFilter) {
// define some default variables
$scope.trsn = {};
$scope.trsn.symbol = "";
...
$scope.preSaveTrsn = function(trsn, formAdd) {
// what to put in here to transfer data to next controller????
};
and then my last controller, I have also nothing in there yet since I can't receive any data....but basically what I want to inject is the transaction data (trsn) which comes from 1st form/controller.
investingApp.controller('PreSaveTrsnController',
function MenuController($scope, $http, trsn) {
console.debug(trsn);
});
Does I have to put something inside the routeProvider somehow? ...or does I have to fill in something special inside the preSaveTrsn function inside my 1st controller??? I'm quite confused with this since all example I find are for saving right away to database, but I can't do that the way I build my app, it really has to be on the second controller for few reasons which I don't think I have to explain here.... Thanks for any help given :)
You may create a lightweight service - value
angular.module('investingApp').value('MySharedValue', {});
And then inject it in both controllers:
TransactionController($scope, $http, $location, $compile, $timeout, transactionDataService, dateFilter, MySharedValue)
And just to assign your shared value to it
$scope.preSaveTrsn = function(trsn, formAdd) {
MySharedValue.trsn = trsn;
};
There are 2 ways to achieve it. First is to declare your model object on $rootScope or on a scope which is parent to both of these controller scope. This way the data gets shared and the changes are available to both controller, irrespective of who makes it.
The second better approach is to create a service which tracks the model update. Inject this service into both the controller. Any controller can ask ask for the model from the service and update it. Since services are singleton, the model changes are shared across controller.
Like
angular.module("myApp",[]).factory('transactionService',[function(){
var service={};
var model={};
service.preSaveTrsn = function(trsn, formAdd) {
//set model here
};
service.getPreSaveTrsn=function() {
return model;
}
return service;
}]);

Resources