Angular Dynamic Field in form not showing in view - javascript

This is baffling. It is such a simple thing, but I'm not able to get it to work. I am adding an input field to the form on a button click (originally). At this point I'm just trying to see any value in the view (hence the simple p tag)
HTML VIEW
<span>Add secondary field</span>
<md-button class="md-fab md-mini" ng-click="vm.addVals()">
<i class="material-icons">add</i>
</md-button>
<div ng-if="moreVal">
<div data-ng-repeat="vl in valHolder.valArr track by $index">
<p>My Value: {{vl.myVal}}</p>
</div>
Controller
function EditFormController($scope, $sanitize, ngToast) {
var vm = this;
vm.addVals = addVals;
$scope.valHolder= {valArr: []};
function addVals(){
var ln = $scope.valHolder.valArr.length;
$scope.valHolder.valArr.push({myVal: 'Test'+ln});
$scope.moreVal = true;
}
}());
I have checked that valArr is being populated with new myVal values on button click. But I cannot see anything in the View. the ng-repeat div is empty. Why is this happening? I have been searching for a solution all day now, but this is so absurd no one seems to have this issue. Don't know what I'm doing wrong. I would really appreciate an answer.

Write below code in your controller:
var self = this;
self.valHolder= {valArr: []};
function addVal(){
var ln = self.valHolder.valArr.length;
self.valHolder.valArr.push({myVal: 'Test'+ln});
self.moreVal = true;
}
Write in your HTML like below:
<div ng-if="moreVal">
<div data-ng-repeat="vl in vm.valHolder.valArr track by $index">
<p>My Value: {{vl.myVal}}</p>
</div>

Your addVal function is not getting called. Please change your HTML view to this-
<span>Add secondary field</span>
<md-button class="md-fab md-mini" ng-click="addVal()">
<i class="material-icons">add</i>
</md-button>
<div ng-if="moreVal">
<div data-ng-repeat="vl in valHolder.valArr track by $index">
<p>My Value: {{vl.myVal}}</p>
</div>
and Controller code to this-
$scope.valHolder = { valArr: [] };
$scope.addVal = function () {
var ln = $scope.valHolder.valArr.length;
$scope.valHolder.valArr.push({ myVal: 'Test' + ln });
$scope.moreVal = true;
}
In case you are using ControllerAs syntax and you have specified controllerAs:"vm", then your code will be below
<span>Add secondary field</span>
<md-button class="md-fab md-mini" ng-click="vm.addVal()">
<i class="material-icons">add</i>
</md-button>
<div ng-if="vm.moreVal">
<div data-ng-repeat="vl in vm.valHolder.valArr track by $index">
<p>My Value: {{vl.myVal}}</p>
</div>
and Controller code to this-
var self = this;
self.valHolder = { valArr: [] };
self.addVal = function () {
var ln = self.valHolder.valArr.length;
self.valHolder.valArr.push({ myVal: 'Test' + ln });
self.moreVal = true;
}

You are using ng-click="vm.addVals()" and $scope in controller.
I think you should use var vm in controller as well. Add these lines:
var vm = this;
vm = {};
and
vm.addVals = addVals;

Related

Knockout click binding doesnt fire on click

Just setup a basic knokcout view model and respective html view, but the click function doesnt fire.
<script>
new myModel.XYZ();
</script>
<div id="bar-1">
<button
title="Get Document"
data-toggle="tooltip"
data-bind="click: getDocument">
<span class="fas fa-file-alt"></span>
</button>
</div>
and my view model is setup as;
myModel.XYZ = function (par) {
var self = this;
self.getDocument = function(submission) {
alert('');
}
ko.applyBindings(self, $("#bar-1")[0]);
};
There's no console error or anything else that could help me find out the issue.
I mostly agree with #erpfast, But if you still want to implement your way, you forgot to declare myModel and added method on Object.
var myModel ={};
myModel.XYZ = function (par) {
var self = this;
self.getDocument = function(submission) {
alert('');
}
ko.applyBindings(self, $("#bar-1")[0]);
};
new myModel.XYZ();
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="bar-1">
<button
title="Get Document"
data-toggle="tooltip"
data-bind="click: getDocument">
Button
<span class="fas fa-file-alt"></span>
</button>
</div>
First, define your model
var myModel = function(par) {
var self = this;
self.getDocument = function(submission) {
alert('');
}
}
Then set your binding
ko.applyBindings(new myModel(document.getElementById("#bar-1")));
JSFiddle

Querystring with multiple parameters in angularjs

i try to produce a querystring in my MEANJS application. The querystring should hold multiply parameters that can be changed with an ng-click. I run into some problems as i try to concatinate the different parameters for the query, here is what i have done so far.
<md-list layout="column" layout-align="center" flex="100" ng-cloak>
<!-- syllableCount -->
<md-list-item>
<label flex="20">Silbenanzahl</label>
<md-button type="button" class="btn btn-sm min-width-45"
ng-click="searchSpec('syllableCount=1')">1
</md-button>
<md-button type="button" class="btn btn-sm min-width-45"
ng-click="searchSpec('syllableCount=2')">2
</md-button>
<md-button type="button" class="btn btn-sm min-width-45"
ng-click="searchSpec('syllableCount=3')">3
</md-button>
<md-button type="button" class="btn btn-sm min-width-45"
ng-click="searchSpec('syllableCount=4')">4
</md-button>
<md-divider ng-if="!$last"></md-divider>
</md-list-item>
<!-- end -->
<!-- syllableStructur -->
<md-list-item>
<label flex="20">Silbenstruktur</label>
<md-button type="button" class="btn btn-sm min-width-45"
ng-click="searchSpec('syllableStructur=einfach')">einfach
</md-button>
<md-button type="button" class="btn btn-sm min-width-45"
ng-click="searchSpec('syllableStructur=komplex')">komplex
</md-button>
<md-divider ng-if="!$last"></md-divider>
</md-list-item>
<!-- end -->
I implemented ng-click for the two listitems for the searchSpec function. The parameters ( for example "syllableCount=2" ) should go into the querystring in the controller file:
$scope.searchSpec = function(attr) {
var result = $http.get('/api/words/?' + attr)
.success(function(result) {
$scope.searchWords = result; // will be used for ng-repeat
console.log($scope.searchWords);
console.log(attr);
});
};
For now it works fine, if i click some one of the buttons the right query gets build up and the output is (on this case) a list of words with the syllableCount of 1,2,3 or 4 OR with a syllableStructure of einfach (easy) OR komplex (complex).
My Goal is that i can have a list of words with, lets say syllableCount 2 AND a syllableStructure of einfach (easy).
what i tried for this was this:
$scope.searchCount = function(attr) {
$scope.count = attr;
};
$scope.searchStruct = function(attr) {
$scope.struct = attr;
};
$scope.searchSpec = function(attr) {
var result = $http.get('/api/words/?syllableCount=' + $scope.count + '&' + 'syllableStructur=' + $scope.struct)
.success(function(result) {
$scope.searchWords = result;
console.log($scope.searchWords);
console.log(attr);
});
};
The two new functions get called in the html from the buttons and i try to concatinate the results to a string. However it did not work. It did not show the results (count=2 AND struct=einfach) If i type it in hardcoded like this:var result = $http.get('/api/words/?syllableCount=' + 2 + '&' + 'syllableStructur=' + einfach) it works fine.
Is it the right way to do it, or am i wrong here?
It looks to me like you are resetting the $scope.searchwords object every time you make a http call, i.e. every click (searchSpec function is called).
What is $scope.searchWords? If you're wanting to continue to add data to it dependent on clicks, you best make an array and push to it, i.e.
$scope.searchSpec = function(attr) {
var result = $http.get('/api/words/?syllableCount=' + $scope.count + '&' + 'syllableStructur=' + $scope.struct)
.success(function(result) {
$scope.searchWords.push(result.data);
});
};
Just make sure to not reassign the $scope.whatever object every time you get a result.
$scope.searchSpec = function(attr) {
var result = $http.get('/api/words/?syllableCount=' + $scope.count + '&' + 'syllableStructur=' + $scope.struct)
.success(function(result) {
$scope[attr].push(result.data);
});
};

append html to the div with AngularJS

How can i pass html through in AngularJS controller ?
Here is my list.html:
<div class="col-xs-3" ng-repeat="item in companyData">
<a ng-click="getPackageInfo({{item.iCompanyID}},'{{item.vCompanyName}}')" class="block panel padder-v bg-primary item">
<span class="text-white block">{{item.vCompanyName}}</span>
</a>
<div id="packagehtml"></div>
</div>
<div id="lp" class="col-md-12 listing-div hidden"></div>
in controller.js:
$scope.pData = [];
$scope.getPackageInfo = function(id,name) {
$scope.name = name;
var summery = SubscriptionoptioncompanylistFactory.getSummary(id);
document.getElementById("lp").classList.remove("hidden");
$('.packages-data').html('');
$('#loading').show();
SubscriptionoptioncompanylistFactory.getPackageInDetail(id).
success(function(data) {
if(data != 0) {
$("#lp").html(summery); // this is used to append the data
document.getElementById("np").classList.add("hidden");
Array.prototype.push.apply($scope.pData, data);
$('#loading').hide();
} else {
document.getElementById("lp").classList.add("hidden");
document.getElementById("np").classList.remove("hidden");
$('#loading').hide();
}
});
};
Here, I have wrote $("#lp").html(summery);, in that div I have to append html which comes from var summery = SubscriptionoptioncompanylistFactory.getSummary(id);. But this is not going to append the data. In console I can see that data comes in summary variable. How can I do?
have a look at below modifications
Use angular ng-show for showing/hiding elements
Use data binding and avoid Jquery like Dom manipulation
<div class="col-xs-3" ng-repeat="item in companyData">
<a ng-click="getPackageInfo({{item.iCompanyID}},'{{item.vCompanyName}}')" class="block panel padder-v bg-primary item">
<span class="text-white block">{{item.vCompanyName}}</span>
</a>
<div id="packagehtml"></div>
</div>
<div id="lp" ng-show="lbVisible" class="col-md-12 listing-div hidden">{{summaryBinding}}</div>
and the controller would look like :
$scope.pData = [];
$scope.getPackageInfo = function (id, name) {
$scope.name = name;
var summery = SubscriptionoptioncompanylistFactory.getSummary(id);
$scope.lbVisible = true; //document.getElementById("lp").classList.remove("hidden");
$('.packages-data').html('');
$scope.loadingVisible = true; //$('#loading').show();
SubscriptionoptioncompanylistFactory.getPackageInDetail(id).
success(function (data) {
if (data != 0) {
$scope.summaryBinding = summery; // $("#lp").html(summery); // this is used to append the data
$scope.npVisible = false; // document.getElementById("np").classList.add("hidden");
Array.prototype.push.apply($scope.pData, data);
$scope.loadingVisible = false; // $('#loading').hide();
} else {
$scope.lbVisible = false; //document.getElementById("lp").classList.add("hidden");
$scope.npVisible = false; //document.getElementById("np").classList.remove("hidden");
$scope.loadingVisible = false; // $('#loading').hide();
}
});
};
your snippet is not showing elements that you use :
np, #loading so just find them and add the `ng-show` with the proper scope variable : `npVisible , lbVisible , loadingVisible`
and note that we add the data using summaryBinding
hope this helps :)

knockout if binding working in laptops, but not working in mobile and tablet

I am trying some thing with if binding from knockout. If value is true I want to show some text and if it is false, I want to show some different text, as given in the code.
When I am opening the page with this html, I am getting the expected results.
But when I am trying to get the result in phones and in kindle tab (working fine in wondows tab), it is not giving the results for the if binding I have used in html.
I tried removing '()' from failStatus and status in html, but it is not working. Is it any issue of binding or I am doing any thing wrong?
Thanks for any help.
function temp()
{
this.inviteeEmailList = ko.observableArray([]);
var emailList = {};
emailList['email'] = {'a#x.y , b#c.n'};
emailList['status'] = ko.observable();
emailList['failStatus'] = ko.observable();
this.showList = function()
{
for(var k in inviteeEmailList)
{
if(some_condition)
{
this.inviteeEmailList()[k]['status'](true);
this.inviteeEmailList()[k]['failStatus']("");
}
else
{
this.inviteeEmailList()[k]['status'](false);
this.inviteeEmailList()[k]['failStatus']("not exist");
}
}
}
}
<div id="foundEmail" data-bind="foreach : inviteeEmailList">
<span data-bind="if: $data.status()">
<span>Success</span>
</span>
<span data-bind="if:(!$data.status() && $data.failStatus()) ">
<span>hello world</span>
</span>
<div data-bind="text:$data.email"></div>
<div data-bind="if:!$data.status()">
<div data-bind="text:$data.failStatus()"></div>
</div><br/>
</div>
Instead of using if binding, I tried using visible binding, which worked properly for me.
Giving code below
function temp()
{
this.inviteeEmailList = ko.observableArray([]);
var emailList = {};
emailList['email'] = {'a#x.y , b#c.n'};
emailList['status'] = ko.observable();
emailList['failStatus'] = ko.observable();
this.showList = function()
{
for(var k in inviteeEmailList)
{
if(some_condition)
{
this.inviteeEmailList()[k]['status'](true);
this.inviteeEmailList()[k]['failStatus']("");
}
else
{
this.inviteeEmailList()[k]['status'](false);
this.inviteeEmailList()[k]['failStatus']("not exist");
}
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foundEmail" data-bind="foreach : inviteeEmailList">
<span data-bind="visible: $data.status()">
<span>Success</span>
</span>
<span data-bind="visible:(!$data.status() && $data.failStatus()) ">
<span>hello world</span>
</span>
<div data-bind="text:$data.email"></div>
<div data-bind="visible:!$data.status()">
<div data-bind="text:$data.failStatus()"></div>
</div><br/>
</div>

Knockout computed observable with access to observableArray

I'm having an issue using a computedObservable. They seem pretty straight forward, but I think my use case might be a little odd. The issue is when onBottom() is called, it doesn't see the items that are in the container.slides() array. Instead, I get "Undefined is not a function".
Since onTop() works fine, it makes me think that it's the relationship between Slide and FeaturedContent that is causing the issue, but I think it should work fine. Any help here would be greatly appreciated.
HTML
<div class="section-block" data-bind="foreach: slides">
<div class="row well">
<div class='control'>
<a href='#' data-bind="click: moveUp, ifnot: onTop">
<i class="fa fa-arrow-up"></i>
</a>
<a href='#' data-bind="click: moveDown, ifnot: onBottom">
<i class="fa fa-arrow-down"></i>
</a>
<span class='pull-right'>Remove</span>
</div>
<h5 data-bind="text: headline"></h5>
<p data-bind="text: image"></p>
</div>
</div>
JS
var FeaturedContent = function() {
var self = this;
self.maxSlides = 14;
self.slides = ko.observableArray([
new Slide({}, "I should be last", "someimg", 0, self),
new Slide({}, "I should be first", "anotherimg", 1, self),
new Slide({}, "I should be second-", "anotherimg", 2, self),
]);
// ... snipped.
};
var Slide = function(contentItem, headline, image, order, container) {
var self = this;
// -- Data
self.contentItem = contentItem;
self.headline = headline;
self.image = image;
self.position = ko.observable(0);
self.onBottom = ko.computed(function() {
return (self.position() === container.slides().length - 1) ? true : false;
});
self.onTop = ko.computed(function() {
return (self.position() === 0) ? true : false;
});
return self;
};
During creating
self.slides = ko.observableArray([
new Slide({}, "I should be last", "someimg", 0, self),
new Slide({}, "I should be first", "anotherimg", 1, self),
new Slide({}, "I should be second-", "anotherimg", 2, self),
]);
in the FeaturedContent your code will create new Slide and use self to get container.slides().length i.e. self is the container but slides() has not created. It's a circle reference. So container.slides() is undefined.
try something like this container.slides() && self.position() === container.slides().length - 1

Categories

Resources