Cannot read property 'insertBefore' of null at forEach.after - javascript

I have a very simple html page where I am loading two different html files using ng-include :-
<body ng-controller="testCtrl">
<div class="panel panel-primary">
<h3 class="panel-heading">Test</h3>
<ng-include src="'View/Details.html'" ng-show="details" />
<ng-include src="'View/Summary.html'" ng-show="summary" />
</div>
</body>
Initially only the details variable is true thus it is loading Details view which looks like this:-
<div class="panel-body">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
</tr>
</tbody>
</table>
</div>
and here is the controller for reference:-
.controller("testCtrl", function ($scope) {
$scope.loadItems = function () {
$scope.items= [
{ id: 1, name: "dummy" },
{ id: 2, name: "dummy1" },
{ id: 3, name: "dummy2" }
];
}
$scope.loadItems();
}
When I load the page it is displaying the data properly but no events are getting triggered (all button click handlers are attached via ng-click & associated with behaviors defined in controller) so I went ahead and checked the console, it is displaying the following error:-
TypeError: Cannot read property 'insertBefore' of null
at forEach.after (myUrl)
at Object.JQLite.(anonymous function) [as after]
I am pretty new to Angular. I saw few threads and tried to manipulate my mark-up code but no luck.

You cant <ng-include/> -- should be <ng-include></ng-include>. Also ng-if is usually better than ng-show, since it reduces amount of result html.
Rest works: plnkr.co/edit/EmUYuHltWaXnjEC6juid?p=preview.

Related

ng-click is not working with return $sce.trustAsHtml in angular js without using html code in html page?

I am implementing data table and displaying some icon in the column. And putting ng-click in the font-awesome icon. But ng-click is not working.
Controller:
this.standardOptions = DTOptionsBuilder
.fromFnPromise(Rl.all('xyz/abc').getList())
.withDOM("<'dt-toolbar'<'col-xs-12 col-sm-6'f><'col-sm-6 col-xs-12 hidden-xs'l>r>" +
"t" +
"<'dt-toolbar-footer'<'col-sm-6 col-xs-12 hidden-xs'i><'col-xs-12 col-sm-6'p>>")
.withBootstrap();
function actionRenderer(data) { // inject $sce if required.
console.log(data);
return $sce.trustAsHtml('<i class="fa fa-repeat cursor-pointer" aria-hidden="true" ng-click="volume()"></i> </a>');
}
this.standardColumns = [
DTColumnBuilder.newColumn('id').renderWith(actionRenderer),
];
function volume(){
alert("-----");
}
HTML
<div class="widget-body no-padding">
<table datatable dt-options="datatables.standardOptions" dt-columns="datatables.standardColumns" class="table table-striped table-bordered table-hover" width="100%">
<thead>
<tr>
<th>Refresh</th>
</tr>
</thead>
</table>
</div>
I putted ng-click="volume()" But it is not working. I have seen links but in these links mentioned ng-bind-html in html page. But in my code I am not coding in html page. Only from java-script append the icon.
1.After using $sce.trustAsHtml, ng-click not working
2.Accessing ng-click when rendered via $sce.trustAsHtml
I am only hard code the column heading like Refresh. And definition append by javascript.

Kendo grid from html table crashes

I have the following html in About.cshtml
<div>
#Html.Partial("_SearchPanel", Model.scM)
</div>
<div class="row">
<div class="col-md-12 table-responsive" id="mapsDiv">
#Html.Partial("~/Views/Maps/_MapDetailsList.cshtml", Model.saVM)
</div>
</div>
_MapDetailsList.cshtml
<table class="table table-bordered table-striped table-bordered" id="MapDetails">
<thead>
....
</thead>
<tbody>
.....
</tbody>
Lots of data binding from model goes into the table and works perfectly until i try to convert it into a kendoGrid
Before adding .kendoGrid script
Script in About.cshtml
<script type="text/javascript">
$(function () {
$("#MapDetails").kendoGrid(
{
//sortable: true,
dataSource: {
pageSize: 5
},
pageable:true
});
});
</script>
then I get the following error:
Cannot read property 'nodeName' of undefined
If I replace #MapDetails in the script with #mapsDiv, nodeName error disappears
and Page nos start appearing as bullet points and datarows appear before the headers
if I say
$(".row").kendoGrid(...
there's madness: even the searchpanel gets paginated
Any clues please?
I have the following scripts/style sheets on page
"~/Scripts/jquery-{version}.js"
"~/Content/bootstrap.css"
"~/Content/Site.css"
"~/Content/freelancer.min.css"
"~/Content/kendo/kendo.common-bootstrap.min.css"
"~/Content/kendo/kendo.common.min.css"
"~/Content/kendo/kendo.default.min.css"
"~/Content/kendo/kendo.bootstrap.min.css"
"~/Scripts/modernizr-*"
"~/Scripts/freelancer.js",
"~/Scripts/freelancer.min.js"
"~/Scripts/kendo/jquery.min.js",
"~/Scripts/kendo/kendo.all.min.js",
"~/Scripts/jquery.unobtrusive-ajax.min.js",
"~/Scripts/kendo/kendo.aspnetmvc.min.js"
I totally had to scrap away this approach and create grid from js. As i didnot have linear data, so had to do lots of work arounds too

AngularJS ng-repeat not binding next value for expressions that used in attributes

Here is my code
<script>
var app = angular.module('TestApp', []);
app.controller('TestCtrl', function ($scope) {
$scope.tests = [
{
id: '1',
name: 'Test 1',
count: '10',
children: [{
name: 'Test Child 1'
}]
},
{
id: '2',
name: 'Test 2',
count: '19',
children: [{
name: 'Test Child 2'
}]
},
{
id: '3',
name: 'Test 3',
count: '18',
children: [{
name: 'Test Child 3'
}]
}
];
});
function test() {
alert($('#testtest').attr('href'));
}
</script>
<div ng-app="TestApp" ng-controller="TestCtrl">
<div class="panel panel-default">
<div class="panel-heading clearfix" ng-repeat="test in tests">
<a id="testtest" data-toggle="collapse" href="#div_{{test.id}}" onclick="test();" class="pull-left" style="padding-top: 7.5px;">{{test.id + ' ' + test.name}} <span class="badge">{{test.count}}</span></a>
</div>
<div id="div_{{test.id}}" class="panel-collapse collapse">
<div class="panel-body">
<table id="tbl_{{test.id}}" class="table table-hover">
<thead>
<tr>
<td>Name</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="child in test.children">
<td>{{child.name}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
I'm trying to create a list of panels, with tables in it.
The outcome is:
When I click the name of the panel, it was suppose to expand the panel body, but the panel body wasn't expanding. So I alert() thehref="#div_{{test.id}}"it showed #div_1 for all three items.
It is suppose to be #div_1, #div_2 and #div_3 just like the 1,2 and 3 number generated on the panel header.
What is my mistake?
P/s: Sorry for the bad explaination
You are ng-repeating only the headers, you need to do it for the panels too, please try this out and let me know:
<div ng-app="TestApp" ng-controller="TestCtrl">
<div class="panel panel-default">
<div class="panel-heading clearfix" ng-repeat="test in tests">
<a id="testtest" data-toggle="collapse" href="#div_{{test.id}}" onclick="test();" class="pull-left" style="padding-top: 7.5px;">{{test.id + ' ' + test.name}} <span class="badge">{{test.count}}</span></a>
</div>
<div id="div_{{test.id}}" class="panel-collapse collapse" ng-repeat="test in tests">
<div class="panel-body">
<table id="tbl_{{test.id}}" class="table table-hover">
<thead>
<tr>
<td>Name</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="child in test.children">
<td>{{child.name}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
Malkus and Fedaykin both pointed out the important concept of development using AngularJS. My answer is just a wrap of these two. I have made a working example here.
Changes that I made:
<a id="testtest" data-toggle="collapse" ng-href="#div_{{test.id}}"
class="pull-left" style="padding-top: 7.5px;" ng-click="selectTest(test)">
{{test.id + ' ' + test.name}}<span class="badge">{{test.count}}</span>
</a>
As you can see, I have used ng-click to pass the select test object to the controller and console.log(test). You will be able to see the object in the console.
$scope.selectTest = function(test) {
console.log(test);
$scope.selectedTest = test;
}
This approach allows you to have the whole object and modify it.
Another change I made is:
<div class="panel-collapse collapse" ng-attr-id="div_{{test.id}}"
ng-repeat="test in tests">
...
</div>
As Fedaykin mentioned, you only ng-repeat the panel header, which means the scope of test is only in the header. You are not able to access the test out of the header, because it is out of scope. Therefor you have to do another ng-repeat on the panel body.
I don't like this approach because it gives you less control what it has to display. And when you are encountering a giant data, you don't want to render all the data to front-end because it will cause latency and etc. So, the best approach is display the selected data when users click the corresponding panel.
Suggestion
Try to using ng-click with ng-show, ng-hide, ng-if to do this.
I see a few things that are giving you trouble:
You want to use ng-href hence the errors with the alerts. Also you should use ng-click not onclick
<a id="testtest" data-toggle="collapse" ng-href="#div_{{test.id}}"
ng-click="test();" class="pull-left" style="padding-top: 7.5px;">
{{test.id + ' ' + test.name}}
<span class="badge">{{test.count}}</span></a>
For the panels that aren't exanding ng-repeat only repeats the element and its contents. The section below starts after the ng-repeat ends. You should also use ng-attr-id to update the ID with a value from the scope
<div ng-attr-id="div_{{test.id}}" class="panel-collapse collapse">
A good rule of thumb with angular:
any time you want to use something from the scope to update an element or element attribute see if angular has a directive to manage it. AngularJS compiles the DOM you should not be accessing or manipulating elements without a directive, in this case ng-href, ng-click and ng-attr-id

Expandable content in tables using AngularJS

I've been following the tutorials for AngularJS over on Egghead. Things are going pretty good, until I decided to try to combine some concepts.
My main.js is located here, due to the fact of the size of the file.
And here's my index.html:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8">
<title>Egghead Videos</title>
<link rel="stylesheet" href="foundation/css/foundation.min.css">
</head>
<body>
<div ng-app="myApp">
<div ng-controller="CardsCtrl">
<table>
<tr ng-repeat="set in cards.sets | orderBy:'releaseDate'">
<td>{{set.name}}</td>
<td>{{set.code}}</td>
<td>{{set.releaseDate}}</td>
</tr>
</table>
</div>
</div>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.min.js"></script>
<script type="text/javascript" src="scripts/main.js"></script>
</body>
</html>
So, as you can see, I have it set up right now to display the set, code, and releaseDate in a table using ng-repeat. What I'm trying to accomplish is every time that you click on a set name, it expands and shows all the cards in that set, showing the name and card number. I've tried wrapping the table in the 'zippy' attribute like the tutorial was doing, but that accomplished nothing. Any ideas or suggestions? Thank you.
So, I'll do this in the table format, but it is weird because it would be within the confines of the first td; you might want to consider a different layout. For visualization sake, I'll just make the set.name into a clickable link, but I believe it can be any element.
Please note that this is not tested; best practice that I've seen on here would be for the question to include either a plnkr.co or jsfiddle.net reference.
View:
<td>
<a href="" ng-click="showThisRow(set)">
{{set.name}}
</a>
<p ng-repeat="card in set.cards" ng-if="showRow">
{{card.number}} : {{card.name}}
</p>
</td>
Controller:
$scope.showThisRow = function (whichSet) {
if (whichSet.showRow == true) {
whichSet.showRow = false;
} else {
whichSet.showRow = true;
}
}
Notes: What this is doing is a nested ng-repeat call, which is shown only if the value of the showRow variable is true. showRow can be instantiated as a method of set (an instance of the first ng-repeat) via the ng-click call, even without being specified within the controller.
I don't know if Angular provides something similar to toggle in jQuery; it would be appreciated if someone who knows that could comment as well.
The trick with selection of individual items of ng-repeat, is the inclusion of an controller in the same element as the ng-repeat. The ng-repeat dedicated controller will contain all the new items generated by the iteration, ng-click calling a function in that controller will do the item selection.
view:
<div ng-controller="TableCtrl">
<table class="table table-condensed table-hover">
<thead>
<tr>
<th>Name</th>
<th>Company</th>
</tr>
</thead>
<tbody ng-repeat="i in invoices"
ng-controller="RowCtrl"
ng-click="toggleRow()"
ng-switch on="isSelected()">
<tr>
<td>{{i.name}}</td>
<td>{{i.company}}</td>
</tr>
<tr ng-switch-when="true">
<td>{{i.invoice}}</td>
<td>{{i.units}}</td>
</tr>
</tbody>
</table>
</div>
Controllers:
.value('invoices', [
{ name:'Jack', company:'Blue Widget Co', invoice:'$3,000,000', units: '555'},
{ name:'Jill', company:'Red widget Co', invoice:'$2,000,000', units: '777' }
])
.controller('TableCtrl', function ($scope, invoices) {
$scope.invoices = invoices;
})
.controller('RowCtrl', function ($scope) {
$scope.toggleRow = function () {
$scope.selected = !$scope.selected;
};
$scope.isSelected = function (i) {
return $scope.selected;
};
});
In the RowCtrl, take note of i from ng-repeat="i in invoices":
$scope.isSelected = function (i) {
return $scope.selected;
};
Heres a working expandable table demo
#cheekybastard This can be simplified further by using a directive.
Directive:
app.directive('cdToggleOnClick', function ()
{
return {
restrict: 'A',
scope:
{
cdToggleOnClick: '='
},
link: function(scope, element, attrs) {
element.bind('click', function () {
if (scope.cdToggleOnClick === true)
{
scope.cdToggleOnClick = false;
}
else
{
scope.cdToggleOnClick = true;
}
scope.$apply();
});
}
}
});
HTML:
<div ng-controller="Ctrl">
<table border=1>
<tr ng-repeat-start="i in invoices" cd-toggle-on-click="toggleRow">
<td>{{i.name}}</td>
<td>{{i.company}}</td>
</tr>
<tr ng-repeat-end ng-if="toggleRow">
<td>{{i.invoice}}</td>
<td>{{i.units}}</td>
</tr>
</table>
</div>
Controller:
app.controller('Ctrl', function ($scope) {
$scope.invoices = [
{ name:'Jack', company:'Blue Widget Co', invoice:'$3,000,000', units: '555'},
{ name:'phil', company:'green Widget Co', invoice:'$1,000,000', units: '545'},
{ name:'Jill', company:'Red widget Co', invoice:'$2,000,000', units: '777' }
];
});
Plunker Demo

Angular.js view doesn't update when nested $scope array is updated

I am trying to make an angular.js view update itself when adding a comment. My code is as follows:
<div class="comment clearfix" data-ng-repeat="comment in currentItem.comments" data-ng-class="{bubble: $first}" data-ng-instant>
<div>
<p>
<span class="username">{{comment.user}}</span> {{comment.message}}
</p>
<p class="time">
10 minutes ago
</p>
</div>
</div>
<div class="comment reply">
<div class="row-fluid">
<div class="span1">
<img src="assets/img/samples/user2.jpg" alt="user2" />
</div>
<div class="span11">
<textarea class="input-block-level addComment" type="text" placeholder="Reply…"></textarea>
</div>
</div>
</div>
the scope is updated on enter:
$('.addComment').keypress(function(e) {
if(e.which == 10 || e.which == 13) {
$scope.currentItem.comments.push({
"user": "user3",
"message": $(this).val()
});
console.debug("currentItem", $scope.currentItem);
}
});
debugging $scope.currentItem shows that the comment has been added to it, however the view doesn't show the new comment. I suspect that the $scope is only being watched on its first level and that this is why the view doesn't update. is that the case? If so how can I fix it?
SOLUTION:
As Ajay suggested in his answer below I wrapped the array push into the apply function like this:
var el=$(this);
$scope.$apply(function () {
$scope.currentChallenge.comments.push({
"user": $scope.currentUser,
"message": el.val()
});
});
Modify the code to wrap inside scope.$apply because you are modifying the property outside the angular scope you have to use scope.$apply() to watch the values
I had to place my form inside the same div controller as the ng-repeat. I had two separate div controllers.
Use $scope.$parent.arrayObjet to modify the parent variables instead of $scope.arryaObject. It worked in my case.
<div class="col-sm-12 col-lg-12">
<div class="outer-container">
<div class="inner-container">
<div class="table-header">
<form id="teamForm" name="teamForm">
<table class="table table-bordered">
<thead>
<!-- Grid header -->
<tbody data-ng-if="(allTeamMembers.length==0)">
<tr>
<td class="text-center height_33_p" colspan="15"> {{noResultFound}} </td>
</tr>
</tbody>
<!-- Existing team member -->
<tbody data-ng-repeat="tm in teammemberDetailsArryobject|orderBy:orderByField:reverseSort" data-ng-form="innerForm_$index" data-ng-class="{'ng-submitted':innerForm_$index.$submitted}">
<tr></tr>
</tbody>
In the code I am deleting one record and add new row programmatically but all the rows are displayed in the ng-repeat rows(including deleted)

Categories