I am pretty new to angular and web development in general and I cannot for the life of me figure out what is wrong with my code. Essentially I'm just trying to add to a table that uses ng-repeat by using $scope.arrayname.push. Let me know if I wasn't clear on something. Here are the relevant files:
My angular file:
var routerApp = angular.module('routerApp', ['ui.router']);
...
routerApp.controller('eventController', function($scope) {
$scope.events = [];
$scope.addEvent = function () {
$scope.events.push ({
name: $scope.eventName,
start: $scope.startDate,
end: $scope.endDate,
location: $scope.locationid
});
// Clear input fields after push
$scope.eventName = "";
$scope.startDate = "";
$scope.endDate = "";
$scope.locationid = "";
};
});
and here is my html file where the input goes:
<div class="jumbotron text-center">
<h2>The Event Page </h2>
</div>
<div class="row">
<div class="col-sm-6" ng-controller="eventController">
<div ui-view="columnOne"></div>
<input value="" type="text" placeholder="Name of Event" ng-model="eventName">
<input value="" type="text" placeholder="Start Date" ng-model="startDate">
<input value="" type="text" placeholder="End Date" ng-model="endDate">
<input value="" type="text" placeholder="Location" ng-model="locationid">
<button ng-click="addEvent()">Add to Event List</button>
</div>
<div class="col-sm-6">
<div ui-view="columnTwo"></div>
</div>
</div>
And the data should be outputed in a table here:
<tbody>
<tr ng-repeat="event in events">
<td>{{ event.name }}</td>
<td>{{ event.start }}</td>
<td>{{ event.end }}</td>
<td>{{ event.location }}</td>
<!---<td>{{ event.link }}</td>--->
</tr>
</tbody>
I am using partial views with routerApp from angular. Here is my plunker: http://plnkr.co/edit/FBoWuEQYhCwtTtNN9Wrk?p=preview
Any help is appreciated!
I had to make a few changes to get this to work. The main issue is that the scope isn't being preserved between your table view and the button press so even though the value is bound (you can console.log(events) and it will output correctly) it doesn't display.
First I named the controller ec and moved it up a level
<div class="jumbotron text-center">
<h2>The Event Page </h2>
</div>
<div class="row" ng-controller="eventController as ec">
<div class="col-sm-6" >
<div ui-view="columnOne"></div>
<input value="" type="text" placeholder="Name of Event" ng-model="eventName">
<input value="" type="text" placeholder="Start Date" ng-model="startDate">
<input value="" type="text" placeholder="End Date" ng-model="endDate">
<input value="" type="text" placeholder="Location" ng-model="locationid">
<button ng-click="ec.addEvent()">Add to Event List</button>
</div>
<div class="col-sm-6">
<div ui-view="columnTwo"></div>
</div>
</div>
Then I changed the controller to point to "this" instead of $scope
routerApp.controller('eventController', function($scope) {
var ec = this;
ec.events = [];
ec.addEvent = function () {
ec.events.push ({
name: $scope.eventName,
start: $scope.startDate,
end: $scope.endDate,
location: $scope.locationid
});
// Clear input fields after push
$scope.eventName = "";
$scope.startDate = "";
$scope.endDate = "";
$scope.locationid = "";
};
});
And finally I changed the ng-repeat to use ec.events
<tr ng-repeat="event in ec.events">
There's probably a better way to do it with services or something like that to share the scope but that's all I could get to work.
Related
Here is clear exampel about forms:
<div ng-form="namesForm_{{$index}}" ng-repeat="name in names">
<input type="text"
name="input_{{$index}}_0"></input>
<!-- ... -->
Ok, but how I should access $valid field from form? E.g this does not work:
{{namesForm_$index.$valid}}
Even {{namesForm_$index}} outputs 0.
It is need to "inline" $index before {{}} resolve a variable name. How to do that?
It's not easy to get it inside of single {{ }} expression, but if you only want to use it in directives accepting expressions without handlebar (like ng-disabled), you can achieve that:
<div ng-app>
<ng-form name="namesForm_{{$index}}" ng-repeat="name in [1, 2]">
<input type="text"
placeholder="{{$index}}"
ng-required="true"
ng-model="test"
name="hey" />
<button ng-disabled="!namesForm_{{$index}}.$valid">
send
</button>
<br />
</ng-form>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
{{ IsFormValid($index) }}
$scope.IsFormValid = function(index) {
var form = angular.element("formName" + index);
return form.$valid;
};
UPDATED
Working example:
{{ IsFormValid($index) }}
$scope.IsFormValid = function(index) {
var form = angular.element(document.getElementById('#bucketForm-' + index);
return form.$valid;
};
New Approach
The below is an example for dynamic ngModel, same can be replicated for form name :
$scope.formData = {};
$scope.formData = {
settings:
{
apiEndpoint: '',
method: 'get'
},
parameters: {}
};
<div class="form-group" ng-repeat="parameter in apiParameters">
<label for="{{parameter.paramName}}" class="col-sm-2 control-label">{{parameter.paramTitle}}</label>
<div class="col-sm-3">
<input type="text" class="form-control" name="{{parameter.paramName}}" id="{{parameter.paramName}}" ng-model="formData.parameters[parameter.paramName]" placeholder="{{parameter.paramTitle}}">
</div>
</div>
How do I access the individual input names defined in a form inside my controller?
rates.rateName
rates.rateBitrate
rates.rateWidth
rates.rateHeight
This does not work: var url = {{ tmp + data.rateName }};
I need to extract one of the input values from the form and append it to the url
to be used with a $http POST. I need to put the rest of the inputs from the form (all together) into the POST as well as json blob.
<div ng-controller="RateCtrlAdd">
<rd-widget>
<rd-widget-header icon="fa-users" title="Rates">
</rd-widget-header>
</rd-widget>
<p></p>
<div class="row">
<div class="col-sm-6">
<form name="myForm" ng-submit="SendData()">
<input class="form-control input-lg" type="text"
placeholder="rate name"
name="rates.rateName"
ng-model="rates.rateName" required/>
<br>
<input class="form-control input-lg" type="text"
placeholder="rate bit rate"
name="rates.rateBitrate"
ng-model="rates.rateBitrate" required/>
<br>
<input class="form-control input-lg" type="text"
placeholder="rate width"
name="rates.rateWidth"
ng-model="rates.rateWidth" required/>
<br>
<input class="form-control input-lg" type="text"
placeholder="rate height"
name="rates.rateHeight"
ng-model="rates.rateHeight" required/>
</form>
</div>
</div>
<div class="row" style="margin-top: 12px;">
<div class="col-sm-6">
<button class="btn btn-success btn" value="Send" ng-click="SendData()">
Add
</button>
<a href="/rates" class="btn btn-danger btn">
Cancel
</a>
</div>
</div>
</div>
'use strict';
angular.module('RDash')
.controller('RateCtrlAdd', ['$scope', '$http', function($scope, $http) {
console.log('RateCtrlAdd - enter...');
$scope.SendData = function () {
var data = $scope.rates;
console.log('RateCtrlAdd - rates from input form: ', $scope.rates);
var tmp = 'http://10.10.15.145:8085/lms/outputstream/';
var url = {{ tmp + data.rateName }};
console.log('RateCtrlAdd - url: ', url);
}; // end function()
console.log('RateCtrlAdd - ...exit');
}]); // end controller()
You cant use binding expression i.e. {{}} in controller. Add it using simple javascript
Try this
var url = tmp + data.rateName;
I am new to AngularJS. I stored the response data in the scope in my controller . But the values stored in scope not getting displayed in the html page.
guest-controller.js
var guestProfileApp = angular.module('guestProfileApp', ['guestProfileServices' ]);
guestProfileApp.controller( 'guestProfileController', [ '$scope', 'guestProfileService', GuestProfileController ]);
function GuestProfileController( $scope, guestProfileService)
{
$scope.getProfile = getProfile;
$scope.saveProfile = saveProfile;
console.log('guest profile controller called');
function getProfile( profileID ){
return guestProfileService.getProfile( profileID ).then( function( response ){
$scope.profileBizObj = response.data;
console.log($scope.profileBizObj);
window.location = "profile.html";
});
}
}
profile.html
<html lang="en" ng-app="guestProfileApp">
<body ng-controller="guestProfileController">
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" placeholder="First Name" id="f_firstName" ng-model="profileBizObj.profileData.nameInfo.firstName">
<div class="input-group-addon"><span class="glyphicon glyphicon-user"></span></div>
</div>
</div>
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" placeholder="Last Name" id="f_lastName" ng-model="profileBizObj.profileData.nameInfo.lastName">
<div class="input-group-addon"><span class="glyphicon glyphicon-user"></span></div>
</div>
</div>
<div class="form-group">
<div class="input-group">
<input type="date" class="form-control" placeholder="Date of Birth" id="f_dob" ng-model="profileBizObj.profileData.nameInfo.birthDate">
<div class="input-group-addon"><span class="glyphicon glyphicon-gift"></span></div>
</div>
</div>
</body>
</html>
When I displayed the response data using
console.log($scope.profileBizObj);
The data is displaying correctly. But when I am moving to "profile.html" and trying to display the profileBizObj data using ng-model the values are not getting displayed.
Here is the output of console.log($scope.profileBizObj);
{"addressList":[],
"customerID":"MYCUST",
"emailList":[],
"formattedName":"JOHN PAWLIW, #388569330",
"phoneList":[],
"profileData":{"createdOn":"2015-11-24T14:05:58",
"customerID":"MYCUST",
"nameInfo":{"createdOn":"2015-11-24T14:05:58",
"firstName":"JOHN",
"lastName":"JOHN PAWLIW",
"mergedObjectState":2,
"middleName":"",
"nameInfoID":12642,
"nameTitle":"MR",
"profileID":7183,
"selectedLocale":"en_US",
"updatedOn":"2015-11-24T14:05:58"},
"profileID":7183,
"selectedLocale":"en_US",
"status":"ACTIVE",
"updatedOn":"2015-11-24T14:05:58"},
"profileID":7183,
}
Please help me as how to resolve this issue . Thank You
In order to display the $scope.profileBizObj in view.html. You can use ng-repeatto iterate through object properties.
<div ng-repeat="item in profileBizObj">
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" placeholder="First Name" id="f_firstName" ng-model="item.profileData.nameInfo.firstName">
<div class="input-group-addon"><span class="glyphicon glyphicon-user"></span></div>
</div>
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" placeholder="Last Name" id="f_lastName" ng-model="item.profileData.nameInfo.lastName">
<div class="input-group-addon"><span class="glyphicon glyphicon-user"></span></div>
</div>
</div>
</div>
This is the fiddle link: https://jsfiddle.net/rrwfu834/2/
window.location = "profile.html"
loads a new page. The new page shares no information with the previous page. It's like hitting reload or typing a new url into the browser window.
Looking at your code, simply try removing that line to see if resolves your issue.
There are several ways to load a template within the current page - the easiest of which is probably ng-include.
You can also use routes or ui.router.
The issue is resolved by making following changes
profiletest.html
<body>
<div ng-app="guestProfileApp">
<div ng-controller="guestProfileController">
<button ng-click="getProfile(1546)">Show Profile</button>
<ng-include ng-if="showProfile" src="'profile1.html'"></ng-include>
</div>
</div>
</body>
guest-controller.js
function GuestProfileController( $scope, guestProfileService)
{
$scope.getProfile = getProfile;
$scope.saveProfile = saveProfile;
console.log('guest profile controller called');
function getProfile( profileID ){
return guestProfileService.getProfile( profileID ).then( function( response ){
$scope.showProfile = true;
$scope.profileBizObj = response.data;
});
}
}
I need to add HTML content on Button Click event using AngularJS. Is it possible??
My index.html
<div class="form-group">
<label for="category"> How Many Questions Want You Add ? </label>
<div class="col-sm-10">
<input type="text" class="form-control input-mini" id="questionNos" name="questionNos" placeholder="Nos." ng-model="myData.questionNos">
<div class="input-append">
<button class="btn-warning btn-mini" type="button" ng-click="myData.doClick()">Generate</button>
</div>
</div>
</div>
I want to add Nos. of HTML divs as per quantity added dynamically..
myApp.js
angular.module("myApp", []).controller("AddQuestionsController",
function($scope) {
$scope.myData = {};
$scope.myData.questionNos = "";
$scope.myData.doClick = function() {
//Do Something...????
};
});
It should be possible. I would data-bind your Divs to viewModel elements, and in your doClick function create the viewModels.
I would avoid directly creating Html in your viewModel.
For example:
<div class="form-group">
<label for="category"> How Many Questions Want You Add ? </label>
<div class="col-sm-10">
<input type="text" class="form-control input-mini" id="questionNos" name="questionNos" placeholder="Nos." ng-model="myData.questionNos">
<div class="input-append">
<button class="btn-warning btn-mini" type="button" ng-click="myData.doClick()">Generate</button>
</div>
<div ng-repeat="q in myData.questions">
<!-- BIND TO Q HERE -->
</div>
</div>
</div>
And in doClick:
$scope.myData.doClick = function() {
var newQuestions = getNewQuestionViewModels($scope.myData.questionNos);
for (var i = 0; i < newQuestions.length; i++) {
$scope.myData.questions.push(newQuestions[i]);
}
};
You have to store questions in collection and do repeat.
DEMO
HTML:
<div>
<input type="text" ng-model="data.qcount">
<button type="button" ng-click="data.add()">Add</button>
</div>
<div>
<div ng-repeat="q in data.questions track by $index">
<pre>{{ q | json }}</pre>
</div>
</div>
JS:
$scope.data = {
questions: [],
qcount: 0,
add: function() {
var dummy = {
'title': 'Q title',
'body': 'Q body'
},
newQ = [];
for (var i = 0; i < $scope.data.qcount; ++i) {
newQ.push(dummy);
}
$scope.data.questions = $scope.data.questions.concat(newQ);
$scope.data.qcount = 0;
}
};
Here is my Knockout ViewModel
$(document).ready(
function () {
var Crime = function (CaseNumber, DateOfIncident, Description) {
this.CaseNumber = CaseNumber;
this.DateOfIncident = DateOfIncident;
this.Description = Description;
}
var crimes = function (items) {
var self = this;
//Data
self.items = ko.observableArray(items)
//operations
self.addCrime = function () {
if ($("#AddCrimeForm").valid()) {
self.crime = new Crime($("#CaseNumber").val(), $("#DateOfIncident").val(), $("#Description").val());
//var JSONObj = { CaseNumber: $("#CaseNumber").val(), DateOfIncident: $("#DateOfIncident").val(), Description: $("#Description").val() };
self.items.push(this.crime);
$("#CaseNumber").val("");
$("#DateOfIncident").val("");
$("#Description").val("");
}
}
self.removeCrime = function (item) {
self.items().remove(item);
}
}
var initialData = new Array();
ko.applyBindings(crimes(initialData), $("#CrimeList")[0])
}
);
Here is my View, in HTML:
<form id="AddCrimeForm">
<div class="panel panel-success">
<div class="panel-heading">
<div class="form-horizontal">
<div class="row">
<div class="col-lg-11">Add a crime incident to the list</div>
<div class="col-lg-1">
<button type="button" class="btn btn-success btn-xs" onclick="addCrime()"><i class="fa fa-plus"></i> Add</button>
</div>
</div>
</div>
</div>
<div class="panel-body">
<div class="form-horizontal">
<div class="row">
<div class="col-lg-6">
<input data-val="true" data-val-number="The field Id must be a number." data-val-required="The Id field is required." id="Id" name="Id" type="hidden" value="">
<div class="form-group">
<label class="control-label col-md-4" for="CaseNumber">Case Number</label>
<div class="col-md-8">
<input class="form-control text-box single-line" data-val="true" data-val-required="The Case Number field is required." id="CaseNumber" name="CaseNumber" type="text" value="">
<span class="field-validation-valid" data-valmsg-for="CaseNumber" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-4" for="DateOfIncident">Date Of Incident</label>
<div class="col-md-8">
<input class="form-control text-box single-line valid" data-val="true" data-val-required="The Date of Incident field is required." id="DateOfIncident" name="DateOfIncident" type="date" value="">
<span class="field-validation-valid" data-valmsg-for="DateOfIncident" data-valmsg-replace="true"></span>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label class="control-label col-md-4" for="Description">Description</label>
<div class="col-md-8">
<textarea class="form-control text-box multi-line" data-val="true" data-val-required="The Description field is required." id="Description" name="Description"></textarea>
<span class="field-validation-valid" data-valmsg-for="Description" data-valmsg-replace="true"></span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
<table class="table table-striped table-hover " id="CrimeList">
<thead>
<tr>
<th>Case Number</th>
<th>Date of Incident</th>
<th>Description</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: items">
<tr>
<td data-bind="text: $data.CaseNumber" class="col-lg-2">Column content</td>
<td data-bind="text: $data.DateOfIncident" class="col-lg-2">Column content</td>
<td data-bind="text: $data.Description" style="text-wrap: normal" class="col-lg-7">Column content</td>
#*<td></td>
<td></td>
<td></td>*#
<td style="text-align: center" class="col-lg-1">
<i class="fa fa-trash-o"></i> Remove
</td>
</tr>
</tbody>
</table>
The error I get when adding an item relates to the binding of the "Remove" link in the table, and is as follows:
Unhandled exception at line 58, column 363 in
http://localhost:49803/Scripts/KnockOut/knockout-3.0.0.js
0x800a138f - JavaScript runtime error: Unable to get property
'removeCrime' of undefined or null reference
Now, I'm not sure what the problem here is, since I am supposed to be binding to the root, since the removeCrime method resides in the root of the ViewModel?
You are setting the removeCrime function on the window object, as crimes function is being executed in the global scope, and this points to the window.
Try using new keyword when setting a viewModel.This will create new object and set it as this.
You should also attach the add method to the window if you want to call it outside of knockout.
Another error is that you are calling remove() on an JS Array not on observable Array.
Here is the working code:
$(document).ready(
function () {
var Crime = function (CaseNumber, DateOfIncident, Description) {
this.CaseNumber = CaseNumber;
this.DateOfIncident = DateOfIncident;
this.Description = Description;
}
var crimes = function (items) {
var self = this;
//Data
self.items = ko.observableArray(items)
//operations
window.addCrime = function () {
if ($("#AddCrimeForm")) {
crime = new Crime($("#CaseNumber").val(), $("#DateOfIncident").val(), $("#Description").val());
//var JSONObj = { CaseNumber: $("#CaseNumber").val(), DateOfIncident: $("#DateOfIncident").val(), Description: $("#Description").val() };
self.items.push(this.crime);
$("#CaseNumber").val("");
$("#DateOfIncident").val("");
$("#Description").val("");
}
}
self.removeCrime = function (item) {
self.items.remove(item);
}
}
var initialData = new Array();
ko.applyBindings(new crimes(initialData), $("#CrimeList")[0])
}
);
I check your code and according to me you are missing the real power of knockout. If you are using knockout than i think there is no need to access values of input fields using jquery selectors.
I have created a js fiddle, check this:
demo fiddle
And the javascript code will look something like:
function crimeRecord(data)
{
var self = this;
self.caseNumber = data.CaseNumber;
self.dateOfIncident = data.DateOfIncident;
self.description = data.Description;
}
//Main view model
function viewModel()
{
var self = this;
self.crimeRecords = ko.observableArray();
self.newCrimeRecord = ko.observable(new crimeRecord({}));
self.addRecord = function(){
self.crimeRecords.push(self.newCrimeRecord());
self.newCrimeRecord(new crimeRecord({}));
};
self.removeRecord = function(record){
self.crimeRecords.remove(record);
};
}
$(function(){
ko.applyBindings(new viewModel());
});
Edit - 1
As you mention doubt in your comment regarding to jquery validation, there is no need to rewrite any validation logic you can use jquery validation with this viewmodel. The following is the one way to use it:
....
self.addRecord = function(){
if($("form").valid())
{
self.crimeRecords.push(self.newCrimeRecord());
self.newCrimeRecord(new crimeRecord({}));
}
else
$("form").showErrors();
};
...
Or you can use Knockout Validation.