Angular.js - Jade, Form Submission - angularjs

I'm new to Angular and I'm building my first realtime page based on the boiler plate from:
https://github.com/jimakker/angular-express-bootstrap-seed
I'm not able to get my first form to submit. In fact, nothing happens when I click the button. Given below are the relevant snippets from the code:
Partial View:
.row
form(ng-controller='RegisterCtrl')
#accordion.panel-group
//- Panel 1
.panel.panel-default
.panel-heading
h4(class='panel-title')
a(data-target='#collapse1', data-toggle="collapse", data-parent="#accordion", class="left-m-1em cursor-pointer") Basic Information
#collapse1.panel-collapse.collapse
.panel-body
.row
.col-lg-2(ng-controller='DropdownCtrl')
select(id="gender", ng-model='register.gender', ng-init="getValues('gender')", ng-options='r.value for r in results track by r.key', chosen, class="form-control", data-placeholder="Gender", data-toggle="tooltip", data-trigger="hover", data-placement="top", title="Gender")
option(value="")
//- More panels in between and finally, Panel 6
.panel.panel-default
.panel-heading
h4(class='panel-title')
a(data-target='#collapse6', data-toggle="collapse", data-parent="#accordion", class="left-m-1em cursor-pointer") Family
#collapse6.panel-collapse.collapse
.panel-body
.row
.col-lg-3.col-lg-offset-5
button(type="button", class="btn btn-success btn-lg", ng-click="saveProfile")
span(class="glyphicon glyphicon-ok-circle")
| Submit
I looked at the rendered output and confirmed that the Submit button is indeed within the form tag.
Controller:
function RegisterCtrl($scope, $http) {
$scope.register = {};
$scope.saveProfile = function(item, event) {
alert("called this!");
var json = {
gender: $scope.register.gender,
marital_status: $scope.register.marital_status,
dob: $scope.register.dob,
height: $scope.register.height,
weight: $scope.register.weight,
complexion: $scope.register.complexion,
health: $scope.register.health
};
var responsePromise = $http.post("/api/register", json, {});
responsePromise.success(function(dataFromServer, status, headers, config) {
console.log(dataFromServer.title);
});
responsePromise.error(function(data, status, headers, config) {
alert("Submitting form failed!");
});
};
}
RegisterCtrl.$inject = ['$scope', '$http'];
I'm not even hitting the first alert statement and I'm totally unsure why. The other controller DropdownCtrl (used for individual form elements) works just fine and I'm able to populate the values dynamically using the controller. Please help me find the missing piece.

The syntax is ng-click="saveProfile()" rather than ng-click="saveProfile"
Note also that this won't pass any arguments to the function, if you want to do that then you need to pass them inside the markup too.

Found the problem. Had some stray code in the controller file that read:
` function MyCtrl2() {
}
MyCtrl2.$inject = [];
function RegisterCtrl() {
}
RegisterCtrl.inject = [];`
And since this was in the file after the actual definition, it messed up the functionality.

Related

AngularJS and DataTables refreshing data

My project outputs results to a DataTable from an AngularJS controller function, but I'm running into some strangeness when I try to modify my search params. The first rendering of the table works as expected. But when I select different options and run the search again, extra rows appear in the table, but the info section shows the previous search's row count, and changing the number of rows shown via the length menu causes the new rows to disappear. Here's my table declaration, using attributes to wire up DataTables:
<table ui-jq="dataTable" ui-options="dataTableOptions" id="search-results" class="display nowrap datatable cell-borders" style="width: 100%;">
And this is my AngularJS controller code:
$scope.dataTableOptions = {
dom: "lfBrtip",
lengthMenu: [[25, 50, -1], [25, 50, "All"]],
language: {
emptyTable: 'No items matched your search criteria'
},
buttons: [
{
text: 'Export',
className: 'button button:hover',
extend: 'csv'
}
]
};
$scope.getItemInfo = function (model) {
$http({
method: 'POST',
url: $scope.getUrl('/My/ServerSide/Url'),
data: { model: $scope.model }
}).then(function successCallBack(response) {
$scope.model.SearchResults = response.data;
}, function errorCallback(response) {
alert("There was an error gathering the entity information. Please try again");
});
};
I'm not sure why submitting new queries with different params doesn't simply update the data in the DataTables table. Any suggestions?
I ended up using a bit of an ugly hack to get this to work. Even DataTables author wasn't sure how to get around the issue of using AngularJS with DataTables, so I had to force a reinitialization every time the form posted. I persisted the search params to localStorage, and called location.reload(). Then when the page loads and the AngularJS init() function runs, I pick up the search params and call the search function from inside an Angular document ready function, like this:
$scope.init = function () {
$scope.ValidationErrors = [];
$scope.model = {};
$scope.model.SearchResults = [];
$scope.model.ItemNumber = localStorage.getItem("itemNumber");
$scope.model.StartDate = localStorage.getItem("startDate");
$scope.model.EndDate = localStorage.getItem("endDate");
angular.element(document).ready(function () {
if ($scope.model.ItemNumber) {
$scope.getItemRecords();
}
});
localStorage.clear();
};
And then of course I clear the localStorage after the query. Not terribly elegant, but it'll have to do for now.

How to persist a success icon in the view after modal function with AngularJS and UI-Bootstrap? (Plunker)

I'm making something that works similarly to this plunker that I created.
In my app I'm using Firebase/AngularFire.
In the plunker you can see that when you check-in to a meeting, the icon changes to a success icon. In my app this is where I store that info in Firebase like this:
$scope.join = function(hash) {
console.log(hash);
var ref = dbRef.ref('meetings/'+hash+'/users')
var meetingInfo = $firebaseArray(ref);
meetingInfo.$add({
date: firebase.database.ServerValue.TIMESTAMP,
user_name: $scope.name,
user: $scope.currentUser
}).then(function(ref) {
var key = ref.key;
var index = meetingInfo.$indexFor(key);
console.log(key, index);
$uibModalInstance.close();
});
};
So the data gets added into Firebase and then the modal closes.
I also have a similar controller and view for listing out the meetings just like in the plunker.
In the plunker I send a variable through $rootScope so it's accessible in the listingController. That works, but as you can see I can only check-in to one meeting, and after I refresh or check-in to another meeting, the check-mark disappears.
I would like to know how to persist this change so that anytime I check-in to a meeting the check-mark will stay. I'm thinking that I need to edit something in my listing controller so that when it grabs the data, it can check to see if someone has checked in to the meeting, and display the checkmark, so here is my Firebase list controller:
app.controller('listController', ['$scope', '$rootScope', '$firebaseArray', '$firebaseObject', '$uibModal', function($scope, $rootScope, $firebaseArray, $firebaseObject, $uibModal) {
var ref = firebase.database().ref('meetings');
var list = $firebaseObject(ref);
list.$loaded().then(function(data) {
$scope.lobbies = list;
});
}]);
EDIT
The way Firebase stores the data is like this:
---meetings
------random hash (key)
---------date
---------name
---------attendees
------------random hash
---------------date
---------------name
When I do my ng-repeat it's like this: ng-repeat="(key, meeting) in meetings" so I can access the meeting data like meeting.name. How should I go about accessing the attendees to check if the current user is in the meeting?
SOLUTION
This question helped me out a lot in addition to the HTML snippet that idan provided
You need to decide where you keep this data and how.
You can, for example, hold a list of attendees in the meeting. Something like:
{
users: {
userid1: {
name: 'Someone'
},
userid2: {
name: 'Someone else'
}
// ...
},
meetings: {
meetingid1: {
location: 'Somewhere',
title: 'Gala',
attendees: {
userid1: true,
userid3: true
// ...
}
}
// ...
}
}
Then you can check if a user attends a meeting to change the button.
Also the ng-if there to change buttons seems too much. You can use ng-class on the button and icon, then you'll have only one button instead of two.
<button class="btn btn-sm" ng-click="open(meeting)" ng-class="user.$id in meeting.attendees ? 'btn-success' : 'btn-primary'">
<i class="fa" ng-class="user.$id in meeting.attendees ? 'fa-check' : 'fa-sign-in'"></i>
</button>
One more thing: strongly recommend to read Angular style guide 1 and Angular style guide 2. Both contain great tips to help you maintain your app easily.

angularjs templates not hiding div from route

It's two page user registeration process depending on the role the second page could be different but the first page will always remain the same. what I want I that user can go forward and backwards on both screens with persistent data. I trying a static page at start and then hide it and add the second template from route.
This is my angular app controller.
app.controller('addlandlordController' , function($scope , $http , $route ,API_URL , $routeParams , uploadService ){
$scope.API_URL = API_URL;
$scope.landVisible = true;
$scope.IsVisible = true;
if( $routeParams.test)
{
scope.$apply(function () {
$scope.IsVisible = false;
});
alert( $routeParams.test);
}
$scope.adduser = function($route){
var data = $.param({
fName: $scope.firstName,
lName: $scope.lastName,
role: 'landlord',
email: $scope.email,
linkId: $scope.linkId,
password: $scope.password,
});
var config = {
headers : {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
}
}
$http.post(API_URL + 'user' , data , config)
.then(
function(response){
//$scope.IsVisible = false;
//alert('success');
},
function(response){
// failure callback
alert('fail');
}
);
}
});
I have a div in html like this,.
<div id="content" class="container1" ng-controller='addlandlordController' >
<div ng-show = "IsVisible">
And following is my route in config,.
app.config(function($routeProvider){
$routeProvider.when('/landlord' , {
templateUrl : 'template/addlandlord.html',
controller : 'addlandlordController',
resolve: {
test: function ($route) { $route.current.params.test = true; }
}
})
});
What I want is that when the user click on the following button.
Create an Account</button>
On click that button #/landlord will be added to the url and the route config code will run and add the other template in ng-view which is happening. Now next step is to hide the old div above in such a way that when user go back one sten only the previous code should show and when user goes again into the next screen only the next template should be visible and mean while data should remain same for the both views.
Issues I am facing is
Css is for template view is missing although the css files are already in the commen header. But appears when a place css in the style within template.
if I hide the first div in the response of adduser then if user go back it still hidden. it doesn't appears unless I refresh the page.
But if went to hide it through route config the value turn false but div never hides.
Please check this
scope.$apply(function () {
$scope.IsVisible = false;
});
You are using $apply on scope, but not in $scope.
And $applyAsync is preferable method to trigger digest without risking of error "$digest already in progress"
$applyAsync example:
$element.on('click', ()=>{
$scope.model.testValue = 'I have been updated not from angular circle';
$scope.$applyAsync();
});
Link to the docs
Nice article to read

ng-click doesn't work with external JavaScript

I am creating an ionic project and I am trying to integrate with Algolia autocomplete.js. I managed to make the search system work, however I added a ng-click on my search results and this function is not working as presented in this codepen that I did as example below:
http://codepen.io/marcos_arata/pen/VKVOky
Inside my algolia's result template:
<a ng-click="add_name({{{ name }}})">
Function that should be run when clicked:
$scope.add_name = function(name) {
alert('User added!');
console.log(name);
}
I tried to inject the results inside the scope but didn't work as well:
autocomplete('#search_name', { hint: false, debug: true, openOnFocus: true },[{
source: index.ttAdapter({ hitsPerPage: 15 }),
templates: {
header: '',
suggestion: function(hit) {
$scope.hit = hit;
return template.render(hit);
}
}
}]);
http://codepen.io/marcos_arata/pen/VKVOky
---- SOLVED ----
Instead of creating a ng-click function inside your templates, you can handle the event click of your search inside your "autocomplete:selected" function and use the dataset and suggestion results.
.on('autocomplete:selected', function(event, suggestion, dataset) {
$scope.name = suggestion.name;
console.log($scope.name);
## create any functions with the suggestion and dataset results inside
});
EDITING THE ANSWER:
Here is the codepen:
Apparently the suggestion keep the name clicked, so you dont need an extra function:
.on('autocomplete:selected', function(event, suggestion, dataset) {
$scope.name = suggestion.name;
console.log($scope.name);
});

Refresh list after server callback in AngularJS

I fetch a collection from the server and I would like to get detail for each item. All requests are received correctly, but the paragraph Loading... doesn't hide.
<h2 ng-repeat-start="server in hypervisors track by server.ip | orderBy:server.ip">
{{server.ip}}
</h2>
<div ng-repeat-end>
<p ng-hide="{{server.loaded}}" class="ng-hide">Loading...</p>
When I uncomment the line in controller before post everything works fine.
vmwareStatusApp.controller('Home', function ($scope, $http) {
$http.post('Home/ListHypervisors').success(function (data) {
$scope.hypervisors = data;
$scope.listLoaded = true;
$scope.hypervisors.forEach(function (item) {
//item.loaded = true; // this line works
$http.post('Home/HostInfo', { 'ip': item.ip }).success(function (data) {
$scope.hypervisors[0].loaded = true;
item.loaded = true;
item.detail = data;
})
.error(function(data) {
item.loaded = true;
item.error = data;
item.displayError = true;
});
});
});
});
There are many posts about refreshing view, but I haven't found any working for me. Neither anti-patter with calling $digest() didn't work, because of multiple callback. Which part of AngularJS tutorial have I skipped?
Just remove the braces from your ng-hide like this
ng-hide="server.loaded"
ng-hide and angular directives should be read like this :
ng-directive = "somethingAngularWillInterpret"
The opposite exemple is in your HTML angular will not know what he should interpret instead of just showing some text
<b>server.loaded</b> will show a bold "server.loaded"
To notice angular that he need to interpret we will use the braces
<b>{{somethingAngularWillInterpret}}</b> will show a bold result of the interpretation
EDIT :
So doing this ng-hide="{{server.loaded}}" is probably saying to angular to interpret the result of the server.loaded interpretation like a var named true or a var named false (just speculation, i need to try it).
Just tested it, this just lead to a syntax error.

Resources