$scope of Same Controller when changing Location Path - javascript

I have this two pages index.html#/view and index.html#/update (view and update are also html files)
Their layout is essentially the same (except that view is for viewing only and update is for editing), they use same directives, search-div with search-div.html as template and result-div with result-div.html
and a common controller PageCtrl
search-div.html
<div>
<form>
<input ng-model="page.id">
<input ng-model="page.type">
<button ng-click="page.cancel()">Cancel</button>
<button ng-click="page.submit()">Submit</button>
</form>
</div>
result-div.html
<div>
<table>
<thead>...</thead>
<tbody>
<tr><td>{{page.retrievedData.id}}</td></tr>
<tr><td>{{page.retrievedData.type}}</td></tr>
// some other retrieved data as rows
// some rows are, for view <td>, for update <input>
<table>
</div>
result-div is obtained by some $http.get.
view.html
<div ng-controller="PageCtrl as page">
<search-div></search-div>
<result-div></result-div>
<button ng-click="page.modify('update', page.id, page.type)">Modify</button>
</div>
update.html
<div ng-controller="PageCtrl as page">
<search-div></search-div>
<result-div></result-div>
<button ng-click="page.save()">Save</button>
</div>
When I click the modify button, the id and type in the search-div of view page should still show on update page, so I did:
(inside PageCtrl)
$scope.modify = function(path, id, type) {
$location.path(path);
$scope.id = id;
$scope.type = type;
};
There was no problem with re-directing to another page, however, the id and type does not reflect in update's search-div. What happens to the $scope from view to update directive? How can I properly pass the values of view $scope to update $scope? I would also like to know how to show result-div in update page with the same result from view page.

Related

How to get the 'ng-repeat'(ed) button text string to the next page

I'm developing a Ionic mobile app & I want to pass the button text (which I'll be getting in a ng-repeat) as a string value to the next page and display the variable in the title bar. How do I achieve this? I tried so many solutions from the web resources but still no luck!
<div ng-repeat="x in list">
<button ng-click="callCustomFn(x.text)">
{{x.text}}
</button>
</div>
Create some service and set its custom variable value to the button text clicked from controller and access it in next page
Your controller :-
$scope.callCustomFn = function(text){
myService.setText(text);
}
Inside new page controller :-
$scope.title = myService.getText();

Form validity using Angular ng-repeat

I have an Angular form that is parsing some JSON data.
I'm rendering using ng-repeat. However, I'm having an issue in that the form never becomes valid when a radio button in each group is selected.
I suspect the issue lies with the ng-model in each input, but I can't seem to figure out the correct way to dynamically create an ng-model inside an ng-repeat.
Form block code:
<form name="posttestForm">
<alert ng-repeat="alert in alerts"
type="{{alert.type}}" close="closeAlert($index)">{{alert.msg}}</alert>
<div class="well question-well" ng-repeat="question in questions">
<p>
<strong>{{question.question}}</strong>
</p>
<ul>
<li ng-repeat="answers in question.answers">
<input ng-model="Q[question.id]"
type="radio" name="Q{{question.id}}" value="{{answers.id}}"
required="" data-key="{{answers.isCorrect}}" />{{answers.answer}}
</li>
</ul>
</div>
<button type="submit" class="btn btn-primary" ng-click="EvaluatePosttest(3)"
ng-show="!TestPassed">
Submit Questions</button>
</form>
Here's a Plunkr that shows the dynamic code and demonstrates the form never turning valid when a radio button in each group is selected.
http://plnkr.co/edit/HQGPIOCdn3TGlE96CpK5?p=preview
And here's a Plunkr using static content displaying it working.
http://plnkr.co/edit/ZFt2VnBfaQjuu73kaNQJ?p=preview
Just add this in your javascript controller
$scope.Q = [undefined,undefined,undefined,undefined,undefined,undefined];
Explanation : you set ng-model as Q[question.id] but Q is undefined so the ng-model won't ever work. You always must initialize variable in the controller. The only case it works not initialize is when you do :
ng-model="test"
if you do
ng-model="test.test"
ng-model="test[0]"
It won't ever work if it's not initialized properly.
You can do a custom form validation inside your controller. In your case:
$scope.Q = [];
$scope.$watch('Q', function (Q) {
$scope.posttestForm.$setValidity('count', Q.length >= $scope.questions.length);
}, true);
Inside that, you can do whatever validation you want.
Here's the working plunkr: http://plnkr.co/edit/7Ww4fjJzkDjifPaZ2QtG?p=preview

Angular update html from another section

I have a couple of places on my project where I'm trying to make a form open up from a different html section. I couldn't find any clear answer on how to do this.
To explain more:
After filling in the form, clicking create does work, it creates the new task, and the task is being created on the server, but it won't show up in the table until I refresh the page and reload the HTML. I do have a function to retrieve the tasks from the server, and it runs, all new tasks are stored in my model (main.items), but the HTML doesn't refresh it.
Example 2:
When I click this edit button, it won't open up the form. The delete button does work, and makes the line disappear, but it's in the same table.
The simplified code:
HTML
<div ng-cotroller="MainController as main">
<div>
<button ng-click="main.openForm()">Add New</button>
</div>
<div ng-show="main.showForm">
<form>
...
</form>
</div>
</div>
...
<table ng-cotroller="MainController as main">
<thead><tr><th>...</th></thead>
<tbody>
<tr ng-repeat="item in main.items">
<td>{{item.id}}</td>
...
<td><i class="..." ng-click="main.openForm()></i></td>
</tr>
</tbody>
</table>
Angular
app.controller('MaintenanceController', ['$http', function($http){
var main = this;
main.items = [];
main.showForm = false;
this.getItems = function(){
$http.get(serverUrl+"/items").success(function(data){
main.items = data;
}
this.openForm = function(){
main.showForm = true;
}
}]);
As shown, both the button "Add New" and the icon in the table call the same function, and the value of showForm does change to true in both cases, but the icon does not open the form, as the HTML does not refresh it because it's not in it's tag (my assumption).
Further down the road, once I get the icon to open the form, I also want to insert the details form the same task from the table into the form, so it can be edited. But for now I just want to open the form.
Can anyone tell me what I'm missing, or point me in a direction to get this to work?
The issue occurs due to two instances of the same controller.
You create the first controller:
<div ng-controller="MainController as main">
Then the second one:
<table ng-controller="MainController as main">
Their scopes are not shared. So when one of them gets updated the second stays the same.
IMO, there is no need for two instances here. But if you really want this approach than you will need to either:
create some base controller with items. then both controllers will inherit this collection and all changes will be updated
put collection to factory.

Angularjs, checking if radio buttons in form have been selected

I'm starting with AngularJS, and I'm building a multi-step form where user has to fill different pages. When finished a page, he's allowed to press a next button and fill the following page.
For the first page, I've built in the HMTL a form (named pageOneForm), with different text input fields, marked as required, and in the relative controller I'm doing this watch:
$scope.$watch('pageOneForm.$valid', function(validity) {
ModelData.actualPageCompleted = validity;
})
And it works like a charme. My model (ModelData) is updated.
I was trying to apply the same logic to the following part of the app, the second page. Instead of input text, the user has to select two options from 2 different radio buttons groups.
So I built in the html a list of buttons via ng-repeat :
<div ng-Controller="PageTwo" ng-show='data.actualPage == 2'>
<form name="pageTwoForm">
<h3>General Information > Knowledge About </h3>
<div>
<b>User</b>
<div ng-repeat="option in userOptions">
<input type="radio" name="userGroups" ng-model="data.knowledgeAboutUser" ng-value="option.id" id="{{option.id}}" required>{{option.text}}
</div>
<div ng-repeat="option in targetGroupUserOptions">
<input type="radio" name = "targetUserGroup" ng-model="data.knowledgeAboutTargetGroup" ng-value="option.id" id="{{option.id}}" required>{{option.text}}
</div>
</div>
</form>
and I've implemented the same code as above in its controller:
$scope.$watch('pageTwoForm.$valid', function(validity) {
ModelData.actualPageCompleted = validity;
})
but apparently it doesn't work, and in my model actualPageCompleted is always true...
What am I doing wrong?
Thanks
I did my best to create a controller with some dummy data to get a fiddle working with your example code. Here is the fiddle You need to force the $digest cycle to update your form's validity state on ng-click for the radio buttons (see this SO post for more details), which is why the method
$scope.forceDigest = function(){
setTimeout(function(){ $rootScope.$$phase || $rootScope.$apply(); });
};
is necessary. Alternatively, you can get rid of the method call and uncomment the html code
<h3 ng-show="false">{{data.knowledgeAboutTargetGroup}}</h3>
<h3 ng-show="false">{{data.knowledgeAboutUser}}</h3>
in the fiddle to force the form object to update as well.
And I would make sure that ModelData.actualPageCompleted is not retaining its true value from when pageOneForm.$valid became true and it was set.
I hope that this helps!

How to collect form data in multiple steps and summarize it

Problem
I have a form which is divided into five different sections. Find the Image below. When a person comes on this page I direct him/her directly to the Summary stage with pre-populated data which is working fine. Where the problem comes is there's an option for the user to go n edit this form by clicking on prev button. After the user changes the value in the previous stages and comes back to the summary stage it still shows them the default information which came through the pre-populated data but when a user submit form it submits the correct info with new edited data.
Is there any way I can refresh or reload it? I'm using the below code to display this summary.
Code
//Button to reach the summary stage
<button type="button" class="next" id="summary" onclick="loadnext(4,5);"><img src="images/next.jpg" alt="" /> </button>
//Display
<tr>
<td>Team Name</td>
<td id='t_name_SUM'></td>
</tr>
<tr>
<td>Team Visibility</td>
<td id='t_visibility_SUM'></td>
</tr>
To better support my comment I'm writing this answer.
What you need to do is provide a mechanism to collect data step by step. Copying HTML into other elements is not a very flexible way to do that.
I created a jsfiddle to demonstrate the idea. It's far from perfect but at this stage it works without making things to complicated.
The basic idea is to have an object to control the flow of the views(steps) the user needs to handle. Each view has a controller associated with it to handle the data.
The views.
<div id="step1" class="view">
<h3>Step #1</h3>
<input type="text" name="name" value="" />
</div>
<div id="step2" class="view">
<h3>Step #2</h3>
<input type="text" name="title" value="" />
</div>
<div id="step3" class="view">
<h3>Step #3</h3>
<input type="text" name="message" value="" />
</div>
The object controlling the flow (only showing the most relevant parts).
var flow = {
...
settings:{}, // settings to save
routes: [
{controller:Step1Ctrl, element:'#step1'},
{controller:Step2Ctrl, element:'#step2'},
{controller:Step3Ctrl, element:'#step3'}
],
...
show: function (index) {
var route = this.routes[index];
if (this.currentController) {
this.currentController.commit();
}
this.index = index;
this.currentController = new route.controller(
this.settings,
route.element
);
}
};
Every time a new view is shown the current controller commits the changes to settings and a new controller is created for the current view.
A simple controller can look like this.
function Step1Ctrl(settings, element) {
var $e = $(element).find('input[name="name"]');
$e.val(settings.name); //set the initial value
this.commit = function () {
settings.name = $e.val(); //save
};
}
Since every controller now commits it's changes to settings it easy to represent that data in any way you like. The fiddle just alerted the collected data but you can easily create another view and another controller to display thse settings.
Also, because every controller has access to the settings it can act upon values that are already in there or check if a combination of settings is even possible or not.

Categories

Resources