Angular ng-repeat works... but no values are bound / displayed (Twig) - javascript

I'm having some issues getting my new Angular project off the ground. I'm going to break off pieces into services and such later on, but for now I just have a controller called DashCtrl in a module called sandpiper.
I want to make a list of div.card elements from the $scope.results array within DashCtrl, additional items append to $scope.results when add-button is clicked, and also to append its $scope.test to the header. What happens, after clicking the button a few times, is this: (Screenshot link because I'm new and don't have reputation points T_T)
$scope.pushit() works and ng-repeat winds up spitting out the proper number of items, but the titles are absent. $scope.test isn't getting read either. I've banged my head against the wall for a couple of hours now and even coded up a little bare-bones Angular test to make sure I wasn't out of my gourd... but I just cannot figure this one out.
Here's my JS (two scripts, minified into /build/sandpiper.min.js later)
var app = angular.module('sandpiper', []);
app.controller('DashCtrl',['$scope',function($scope){
$scope.test = "Header"
$scope.results = [
{
title: "Test Item 1",
file: "12345978-My-Test-Document.pdf",
type: "PDF",
tags: ['pdf','test','foo','bar'],
image: "static/img/pdf.png"
}
]
$scope.pushit = function(){
$scope.results.push({
title: "Test Item 1",
file: "12345978-My-Test-Document.pdf",
type: "PDF",
tags: ['pdf','test','foo','bar'],
image: "static/img/pdf.png"
})
}
}])
And here's my HTML (unrelated portions are omitted)
<!DOCTYPE html>
<html lang="en">
<head>
(...)
<!-- bower:js -->
<script src="../bower_components/jquery/dist/jquery.js"></script>
<script src="../bower_components/materialize/bin/materialize.js"></script>
<script src="../bower_components/angular/angular.js"></script>
<!-- endbower -->
<script src="/build/sandpiper.min.js"></script>
</head>
<body ng-app="sandpiper">
<main>
<div class="container" id="content-root">
<div id="dash-wrapper" ng-controller="DashCtrl">
<h3>Test {{ test }}</h3>
<a ng-click="pushit()" class="btn-floating btn-large waves-effect waves-light" id="add-button">
<i class="material-icons">add</i>
</a>
<nav>
(...)
</nav>
<div class="row" id="results-container">
<div class="col s12 m4 l3" ng-repeat="item in results">
<div class="card">
<div class="card-content">
<span class="black-text">{{ item.title }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
(...)
</body>
</html>
Any help would be greatly appreciated; thanks in advance. Hope it's not something really stupid...
(Also this is my first post here, so if I'm doing anything wrong let me know)

Well... the issue was obvious enough. I singled out my CSS includes (I'm using Materialize) and determined that that wasn't the issue-- it was actually that I was using Twig, a PHP template engine that also uses mustache notation for variables. My bindings were being stripped right out by the backend before they even reached the browser. Cannot believe I didn't realize that.
For anyone else who's having this issue, try using a different Angular delimiter or using a different tag_variable pattern for Twig.

Related

Telling angular not to parse certain HTML block

For the context I'm building syntax highlighting for my angular (1.5.8) application. For syntax highlighting I use Prism.js which unfortunately can't highlight my code when I use ng-include in my HTML. Quite understandable since it introduces asynchronity. So to overcome the problem I'm creating an angular directive so that I can write something like this:
<prism lang="html">
<md-toolbar layout layout-align="end center"></md-toolbar>
</prism>
Then in my directive I'm runnin the contents of the directive through Prism.highlight(transclusion, Prism.languages[this.lang]) so far so good. It works, but the only problem is, that angular parses my transclusion beforehand and modifies my input html that it adds additional classes because of my used layout and layout-align directives.
Here lies my question. Can I tell angular that "do not parse this chunk of code"?
Edit: I tried to wrap the input in <pre></pre> but that didn't help. Angular still parsed it and added classes.
Edit2: While I'm writing this I have an idea to put html elements outside of angular context giving them unique id. Then writing <prism code-id="some-unique-id"> then the directive could fetch the dom elem referenced by that uid and include it in the dom. Well, ugly af but could work am I right?
Edit3: I'm extending the post with more code so that you get the whole picture
1: In styleguide.html
<!-- MATERIAL DESIGN -->
<div id="material">
<h1>Material design assets</h1>
<div ng-include="'./material.html'"></div>
</div>
2: In material.html
<section>
<h2>Dialog</h2>
<md-button class="md-accent">Open sample dialog</md-button>
<prism lang="html">
<md-toolbar class="md-primary">
<header class="md-toolbar-tools">
<h3 class="md-headline">{{ 'Dialog title' | translate }}</h3>
<!-- SPACER -->
<span flex></span>
<md-button class="md-icon-button" ng-click="ctrl.close()"><i class="material-icons">close</i></md-button>
</header>
</md-toolbar>
<md-dialog-content>
<div class="md-dialog-content">
<!-- Content here -->
</div>
</md-dialog-content>
<md-dialog-actions layout-padding layout layout-align="end center">
<!-- stuff here -->
</md-dialog-actions>
</prism>
</section>
3: In the component
class PrismHighlighter {
static get $descriptor() {
return {
controller: PrismHighlighter,
template: `
<pre>
<code class="language-{{$ctrl.lang}}">
<ng-transclude class="transclusion"></ng-transclude>
</code>
</pre>
`,
transclude: true,
bindings: {
lang: '#'
}
}
}
static get $inject() {
return ['$element'];
}
constructor($element) {
this.element = $element;
}
$postLink() {
const codeElem = this.element.find('code');
const transclusion = $(this.element).find('ng-transclude').html();
const hCode = Prism.highlight(transclusion, Prism.languages[this.lang]);
codeElem.html(hCode);
}
}
module.component('prism', PrismHighlighter.$descriptor);
4: And the output
Now you can clearly see that there are a lot of angular added things there what I don't want :/
Use ng-non-bindable directive around it.
For Angular 1.x you can just use:
<div ng-non-bindable>
</div>
For angular 2.x this check this post that shows how to do the same.
Reference:
https://docs.angularjs.org/api/ng/directive/ngNonBindable

Passing value out of uib-accordion scope to the parent scope

I am using the uib-accordion directive from ui-boostrap for AngularJS.
I have a question about passing value out of the transcluded directive, uib-accordion-group.
When simply setting a variable to ng-model inside the accordion, it will be attached to the accordion scope, rather than the parent main scope, though it looks like it is in the main scope due to the transclude directive.
In order to pass the value inside the accordion out to the main scope, I need to do something like ng-model="$parent.$parent.$parent.data2 which seems wrong.
Is there a way to do it gracefully?
angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('AccordionDemoCtrl', function($scope) {
});
<!doctype html>
<html ng-app="ui.bootstrap.demo">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular-animate.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.14.3.js"></script>
<script src="example.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="AccordionDemoCtrl">
<script type="text/ng-template" id="group-template.html">
<div class="panel {{panelClass || 'panel-default'}}">
<div class="panel-heading">
<h4 class="panel-title" style="color:#fa39c3">
<a href tabindex="0" class="accordion-toggle" ng-click="toggleOpen()" uib-accordion-transclude="heading"><span
ng-class="{'text-muted': isDisabled}">{{heading}}</span></a>
</h4>
</div>
<div class="panel-collapse collapse" uib-collapse="!isOpen">
<div class="panel-body" style="text-align: right" ng-transclude></div>
</div>
</div>
</script>
<uib-accordion close-others="oneAtATime">
<uib-accordion-group heading="Static Header, initially expanded" is-open="true">
<div>
Simple data model
<input type="text" ng-model="data" />Anti-pattern data2 model
<input type="text" ng-model="$parent.$parent.$parent.data2" />
</div>
<div>
I read "{{data}}" inside the accordion
</div>
<div>
I read "{{data2}}" inside the accordion
</div>
</uib-accordion-group>
</uib-accordion>
<div>
How do I read "{{data}}" OUTSIDE the accordion
</div>
<div>
Data2 seems fine "{{data2}}" OUTSIDE the accordion
</div>
</div>
</body>
</html>
I had a related issue quite recently, and I ended up modifying the ui-bootstrap-tpls-0.14.3.js file. On line 239 you can see I've added a property called 'model' to the accordion directive's scope object.
scope: {
heading: '#', // Interpolate the heading attribute onto this scope
isOpen: '=?',
isDisabled: '=?',
model: '=' // Custom property added
},
Then in the controller, I've added an object called item1 to the controller's scope and given it a property called name:
$scope.item1 = {
name: 'test1'
};
Lastly, add a 'model' attribute to the accordion group directive and specify item1 as the value to pass into the accordion directive:
<uib-accordion-group model="item1" heading="Static Header, initially expanded" is-open="true">
You should now be able to set the object's property values in the accordion as well as access them outside of the directive.
Here's a plunk with your code modified to work.
http://plnkr.co/edit/44x8pH?p=preview
I'm not super happy with modifying the UI bootstrap file, but I couldn't come up with a better way to do it. Obviously you'll need to have your own copy of the file stored locally so you can modify it, and I'd suggest adding .custom to the filename to remind you that it's been modified. Probably pop in some comments too so you can migrate any changes you make to a future version of it in case you want to upgrade.
I know it may be very late, and a little bit of purpose, but I ran into a similar issue: I had a value to pass to the template. Inspired by Chris answer, I found a hack that does’nt change uib files:
I passed the value I want to ng-disable, which I used as a temporary variable.
<div uib-accordion-group ... is-disabled="color">
Then in my accordion template, I put isDisabled back to it’s default false value.
<div class="panel-heading" ng-init="color = isDisabled; isDisabled = false">
After this you can use the color angular variable anywhere in the template.
Here is the corresponding plunker : https://embed.plnkr.co/ExktoE4RCXFrn6SoYZIR/
note: It may also work to pass an object in which you have a value containing isDisabled wanted value ({foo: 'bar',.., isDisabled: true}). And then you pass this value back to isDisabled

Angular ng-sortable - Basic example of how it works

SITUATION:
Hello guys! In my app i have a sort of kanban: there are some columns, each containing a list of items.
I need to drag and drop items among columns and reorder them inside the same column.
I have tried before three angular modules related with drag and drop (first two) and reordering (third):
ngDraggable: https://github.com/fatlinesofcode/ngDraggable
Angular dragdrop: https://github.com/codef0rmer/angular-dragdrop
Angular ui-sortable: https://github.com/angular-ui/ui-sortable
They are nice, with good documentation, but it seems not possible to drag and drop and reorder at the same time.
Then i found another module:
ng-sortable: https://github.com/a5hik/ng-sortable
It seems to be exactly what i need.
But the documentation is not so clear. I am not able to understand how to set it up.
QUESTION:
Can you show me please how to set it up?
There is a plunker with a good and clear example?
Thank you!
Minimal ng-sortable Setup (No need for bower. Bower is confusion for semis like me, too.).
This is the minimum setup to get a full sortable Array with ng-sortable, that worked for me.
Load necessary Javascripts
Load angular.js
Load ng-sortable.js (Find this in dist folder in
downloaded .zip file https://github.com/a5hik/ng-sortable)
Load your app.js
Load the as.sortable into your app
var app = angular.module('app', ['ngRoute', 'as.sortable']);
Load your AppController.js
Load necessary Stylesheets
(Find both in dist folder in downloaded .zip file https://github.com/a5hik/ng-sortable)
Load ng-sortable.css
Load ng-sortable.style.css
Create ul with necessary attributes ( data-as-sortable data-ng-model="sortableList" )
Add data-as-sortable-item to li
Insert div with data-as-sortable-item-handle into li
<!DOCTYPE html>
<html>
<head>
<title>NG-Sortable</title>
<script type="text/javascript" src="js/angular/angular.js"></script>
<script type="text/javascript" src="js/sortable/ng-sortable.js"></script>
<script type="text/javascript" src="js/app.js"></script>
<script type="text/javascript" src="js/AppController.js"></script>
<link rel="stylesheet" type="text/css" href="css/ng-sortable.css">
<link rel="stylesheet" type="text/css" href="css/ng-sortable.style.css">
</head>
<body ng-app="app" ng-controller="AppController">
<ul data-as-sortable data-ng-model="sortableList">
<li ng-repeat="item in sortableList" data-as-sortable-item>
<div data-as-sortable-item-handle>
index: {{$index}} | id: {{item.id}} | title: {{item.title}}
</div>
</li>
</ul>
</body>
</html>
// app.js (Your file)
var app = angular.module('app', ['ngRoute', 'as.sortable']);
// AppController.js (Your file)
app.controller('AppController', [
'$scope',
function ( $scope) {
$scope.sortableList = [
{
id : "id-000",
title : "item 000"
},
{
id : "id-001",
title : "item 001"
},
{
id : "id-002",
title : "item 002"
}
];
}
]);
It would help if we knew what you mean by "setting it up" (whether you mean actually adding it to the project, or how to use it). It would also help if we knew what stack, if any, you were installing this on.
To Install
The install instructions are under the "Usage" section of their Git page.
Run bower install ng-sortable or bower install ng-sortable -save if you're using yeoman
Add the paths to ng-sortable.min.js,ng-sortable.min.css, and ng-sortable.style.min.css to your project, where you add these is dependent on what stack you're using.
Add ui.sortable as a dependency to your app or module. Again, where this goes is dependent on your stack.
To Use
<ul data-as-sortable data-ng-model="array">
<li ng-repeat="item in array" data-as-sortable-item>
<div data-as-sortable-item-handle>
{{item.data}}
</div>
</li>
</ul>
Where "array" is the array of items you're sorting.
This will work out of the box, but if you need custom logic, change data-as-sortable to data-as-sortable="CustomLogic" Where "CustomLogic" is a method in your controller that overrides the default behavior. For more details on how to add custom logic check their Git page under the section "Callbacks" and "Usage".
I just upload a simple example of this awesome library. I have two divs side by side, you can drag divs from one to the other. I'm using static data. Please check it out.
https://github.com/moytho/DragAndDropAngularJS/tree/master/DragAndDrop or as you asked for you can check it out here https://plnkr.co/SRN4u7
<body ng-controller="dragDropController">
<h1>Example</h1>
<div class="container">
<div id="row" class="row">
<div id="assignedEmployees" class="col-lg-5" style="border: 5px solid red;">
<div class="card" as-sortable="sortableOptions" data-ng-model="data.projects">
<div ng-repeat="project in data.projects" as-sortable-item>
<a title="Add card to column" ng-click="setDate(project)">
<i class="glyphicon glyphicon-plus"></i>
</a>
<div as-sortable-item-handle>{{project.FirstName}}</div>
</div>
</div>
</div>
<div id="freeEmployees" class="col-lg-5" style="background-color:lightgray;border:5px dashed gray;">
<div class="card" as-sortable="sortableOptions" data-ng-model="data.employees">
<div ng-repeat="employee in data.employees" as-sortable-item>
<div as-sortable-item-handle>{{employee.FirstName}}</div>
</div>
</div>
</div>
</div>
</div>

AngularJS ng-repeat display content in separate view

I'm working on a basic news feed app. What I need is for a specific news article, entry.content, to display in a separate view after a click. Both controllers have access to the data, but I need a synchronized click event so the second controller knows which specific article to display. I've been working on this for awhile & couldn't find relevant links on google or here where a secondary view was involved. I need a separate view b/c I have to add a lot more HTML to that page & eventually click(previous/next) between articles. I have an example which is working where the click event happens, but the content displays in the current view then hides after click.
I have a Plunker: http://plnkr.co/edit/lk66pRb7A6DkGM7NQKF7?p=preview
Here is the index.html code:
<body ng-app="FeedApp">
<h1>News Feed</h1>
<div ng-controller="NewsCtrl">
<div id="main">
<div ng-view=""><!-- angular yield --></div>
</div> <!-- main -->
</div> <!-- NewsCtrl -->
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="main.js"></script>
</body> <!-- FeedApp -->
Here is the home.html code:
<div ng-repeat="new in news">
<h3 ng-repeat="entry in new.entries" ng-if="$index < 3">
{{entry.title}}
</br>
Display this story</br>
Desired: click this Link, go to #/article & display this story
<p class="news-entries" ng-show="show" ng-bind-html="TrustSnippet(entry.content)"></p>
</h3>
</div> <!-- new in news -->
Currently, in the article.html file I only have a back button as I'm not sure what to put in there. All other code is in the Plunker, but I can add here if it will help.
I was thinking this might be be solved using current $index value, but I just don't know at this point.
Any help is appreciated.
You probably just want to use $routeParams like so:
here's a Plunker
route
.when("/article/:articleId", { . .
Link
<a href="#/article/{{$index}}" . . .
Param
FeedApp.controller("ArticlesCtrl", ["$scope", "$routeParams", '$http',
function($scope, $routeParams, $http) {
var index = $routeParams.articleId;
Article Object
$scope.article = $scope.news[0].entries[index];
I would omit the entries bit altogether and I would probably use a factory to manage/maintain the data.

AngularJs Prerender

PREFACE: I have an AngularJS application with a controller. In the view of this controller I fill a ng-repeat with a list using a JSON object. If I have a slow device such as a phone, the render can be so slow that I can view an empty page for a while before the content arrives some seconds later.
QUESTION: How can I show a pre-load while I wait for the render? Is there some trick or event I can bind to to show a "Waiting" row then hide this row and show the list rendered (when complete).
Thanks all.
P.S. Without jQuery and friends, AngularJS only.
use ng-cloak
plnkr: http://plnkr.co/edit/lgNSdTrMMexHykUBIqnT?p=preview
this example is very much applicable and is NOT LIMITED to ng-repeat, if you download this be reasonable -- put a comment please
NOTE: this Genius example is working, put a comment please if you will downvote it
althought the example uses manual bootstrapping, the behavior is the same. it just use manual bootstrap to demonstrate what it would look like if angularjs is not done bootstrapping yet.
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.js"></script>
<script>
function jsBootStrap() {
console.log('bootstrapping');
angular.bootstrap(document);
}
angular.module("ng").run(function($rootScope){
$rootScope.DisplayMyData = "AngularJS Loves Noypi";
});
</script>
<style>
.preview{
display:none;
}
.ng-cloak.preview {
color:blue;
display:block!important;
}
.ng-cloak.realview {
display:none;
}
</style>
</head>
<body>
<div class="ng-cloak preview">
I was shown before AngularJS. <br/>
Credits <u>ngtutorial.com/learn/bootstrap</u>.
</div>
<div class="ng-cloak realview">
<span ng-repeat="i in [1,2,3,4]">
{{$index}} = {{DisplayMyData}}<br/>
</span><br/>
</div>
<button onclick="jsBootStrap()">bootstrap document</button>
</body>
</html>
how about
<p ng-show="list.length<1">Waiting...</p>
show loading until data is not load
<p ng-hide="list.length">Loading... or here can set a loading image path in img tag</p>
when json data find it will show
<p ng-show="list.length">
<div ng-repeat="list">// your json data in list
</div>
</p>

Categories