Recompile block modified by external scripts - javascript

I have to use a framework that modifies my DOM. Here is some example HTML that gets used:
<div id="testID" ng-show="example === 'show'">Some Content</div>
wil be modified by the Framework to something like this:
<div id="wrapperOne">
<div id="wrapperTwo">
<div id="testID" ng-show="example === 'show'">Some Content</div>
</div>
</div>
This gets done by calling a JS function like this one:
framework.wrap($("#testID"));
As you see, the framework wraps the old HTML with some other elements.
My problem is, that Angular does not show the div, when $scope.example becomes 'show'. Without using the framework, it works fine, I think the problem is, that angular compiles the DOM before the framework changes it. The framework has to wait for an ajax request, so just including the angular scripts after it does not work.
I am searching for a solution to force angular to "recompile" the whole DOM, better some parts of it.
Is this the right proposal, or is there any other way to do this? Just omitting the framework isn't the solution as I have to use it.
Thank you very much,
-Lukas

Use a custom directive with ng-transclude
I've created a fiddle - http://jsfiddle.net/zghuoxhb/2/
directive:
.directive('myWrapper', function () {
return {
restrict: 'E',
templateUrl: "my-wrapper-template.html",
replace: true,
transclude: true,
scope: false
};
})
html:
<my-wrapper>
<div id="testID" ng-show="example === 'show'">Some Content</div>
</my-wrapper>
output:
BTW excellent question, this is a good use case to showcase the awesomeness of angular

Related

Angularjs loading JQuery in partial pages

I have a LAMP website that i am trying to convert to be built on MEAN and I've split the index page into partials so i could have a SPA.
I am completely new to MEAN but i'm slowly learning and trying things however i'm now stuck on JQuery slider plugin that I am using in one of my partials and it does not load any images in the placeholder when the website is ran.
I know that i am supposed to use directives so that JQuery function is loaded after the partial page is loaded into the main page and hence why nothing is being displayed where the slider should be.
This is my partial page that contains the snippet of the slider for a single image (there are 3 of these 'li' blocks at the moment for 3 images):
home.html
<div id="pm-slider" class="pm-slider">
<ul class="pm-slides-container" id="pm_slides_container">
<li data-thumb="public/app/img/home/slide1a.jpg" class="pmslide_0"><img src="public/app/img/home/slide1.jpg" alt="img01" />
<div class="pm-holder">
<div class="pm-caption">
<h1>Medical professionals</h1>
<span class="pm-caption-decription">
that you can trust
</span>
learn more <i class="fa fa-plus"></i>
</div>
</div>
</li>
</ul>
</div>
My index.html file contains div ng-view tag where all of home.html should go.
app.js contains this code for routing and I know that here should go the .directives function for the JQuery plugin
var digiProm = angular.module('digiProm', [
'ngRoute']);
digiProm.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/', {
templateUrl: 'public/app/partials/home.html'
})
.when('/services', {
templateUrl: 'public/app/partials/services.html'
})
.otherwise({
redirectTo: 'partials/home.html'
});
}]);
After watching multiple videos as well as tutorials i can't figure out how i should write my directive function to work.. I am trying to work out how to use this type of format
digiProm.directive('slider', ['$rootScope', function($rootScope) {
return {
restrict: 'EA',
templateUrl: '/path/to/template',
link: function(scope, iElement, attrs) {
//attrs references any attributes on the directive element in html
//iElement is the actual DOM element of the directive,
//so you can bind to it with jQuery
$(iElement).bxSlider({
mode: 'fade',
captions: true
});
}
};
}]);
Is the templateUrl here supposed to be the path to the jquery file for the slideshow?
What the heck would go inside the link: function(...) ?? This script has been shown as an example on how to use the bxSlider and i'm trying to use a Pulse PM-Slider so not sure what functions i'm supposed to call for it to load after the partial has been loaded...
Any kind of help is much appreciated.
Thank you in advance
If the directive is only activating on an element that already exists in another template then you don't need templateUrl.
That is used to be able to inject html into an element. in other words a directive can define it's own template
Also the restrict is to tell directive whether to look for E-an element , or A an attribute or C- a class.
I suggest you add an attribute since it makes it easier to see later on in the markup
<div slider id="pm-slider" class="pm-slider">
Then remove templateUrl from your directive declaration object.
Also note that when jQuery is included in page before angular.js iElement is already a jQuery object so you can just use iElement.bxslider({....})

Custom directive with ng-repeat (outside and inside), replace and templateUrl

I've checked various ressources and all leads to a bug that was closed long ago. Here is a similar issue, but I think mine is slightly different and persists up to at least angular.js 1.5.
I'd like to validate, if this is a new angular bug or if I missed something, since I'm relatively new to angular.
My problem
Check this plunker for a short demo of the issue
I've got a directive <infos> rendered inside a ng-repeat block
<body ng-controller="MainCtrl" class="container">
<div ng-repeat="item in items">
<h2>{{item.title}}</h2>
<infos></infos>
</div>
</body>
The <infos> directive has a ng-repeat block on its first element
<div ng-repeat="(infoId, color) in item.infos">
<p style="background: {{color}}">{{color}}</p>
</div>
The directive is loaded with templateUrl and replace:true.
.directive('infos', function() {
return {
restrict: 'E',
replace: true,
templateUrl: 'infos.html'
};
})
The unexpected result:
When rendered, the directives of all iterations of the surrounding ng-repeat are rendered on the last ng-repeat of the outside loop and not as expected on each iteration of the surrounding ng-repeat. Check the plunker demo for a better understanding, what's going wrong.
Workarounds
I found several workarounds to the problem:
Wrapping the ng-repeat element in the directive by any other element
<div>
<div ng-repeat="(infoId, color) in item.infos">
<p style="background: {{color}}">{{color}}</p>
</div>
</div>
Leaving away the replace: true
Using template instead of templateUrl. Inlining the template code.
Using <script type="text/ng-template" id="infos.html">... to load the template
There might be another solution, using the $templateCache but I couldn't figure out how to preload the template, yet.

How would I create something similar like this in AngularJS

Having a hard time grasping AngularJs.. How would you build something like this simple textfields and animations in AngularJS? I had been looking into using directives but it just isn't adding up to me much. I had been trying to base this from what I learned online but was not having much luck
http://codepen.io/yusufbkr/pen/RPBQqg
HTML:
<div class="materialContainer">
<div class="title">LOGIN</div>
<div class="input">
<label for="name">Username</label>
<input type="text" name="name" id="name">
<span class="spin"></span>
</div>
<div class="input">
<label for="pass">Password</label>
<input type="password" name="pass" id="pass">
<span class="spin"></span>
</div>
<div class="button login">
<button><span>GO</span> <i class="fa fa-check"></i></button>
</div>
Forgot your password?
<div class="title">REGISTER</div>
<div class="input">
<label for="regname">Username</label>
<input type="text" name="regname" id="regname">
<span class="spin"></span>
</div>
<div class="input">
<label for="regpass">Password</label>
<input type="password" name="regpass" id="regpass">
<span class="spin"></span>
</div>
<div class="input">
<label for="reregpass">Repeat Password</label>
<input type="password" name="reregpass" id="reregpass">
<span class="spin"></span>
</div>
<div class="button">
<button><span>NEXT</span></button>
</div>
just use the codepen link ( http://codepen.io/yusufbkr/pen/RPBQqg ), stackoverflow won't let me input the rest of the code...
Thanks! Any help would be incredible
I'm just learning Angular myself. From what I know, you're on the right track to be thinking of directives for swapping out interactive parts of the DOM. I suspect you'll also be needing ui-router for dealing with the widget outcomes (I hear it's the industry standard, vs the built-in ngRouter).
I'm partly writing this out to make sure I understand it, so I hope other, more knowledgeable people will come by and answer any questions you have about it (or point out where I'm misundertanding something.)
So you bring the webpage into the Angular world by, for instance, making the <html></html> tags into <html ng-app="yourApp"></html>. The unchanging html that will be the same on every view is in the index.html file. Put the html for the boxes is in another html file, say box.html. On the index.html file in the place where you want to have your boxes appear, put <div ui-view></div>. The ui-view connects to ui-router. Down at the bottom of the index.html right before closing the body tag, put
<script src="lib/angular/angular.js"></script>
<script src="lib/angular-ui-router/release/angular-ui-router.js"></script>
<script src="app/app.js"></script>.
In app.js, you put something like,
angular.module('yourApp', [
'yourApp.box',
'ui.router'
])
.config(function($stateProvider, $urlRouterProvider, $httpProvider) {
$urlRouterProvider
.otherwise('/signin/child');
$stateProvider
.state('box', {
url: '/signin',
templateUrl: 'app/box/box.html',
controller: 'BoxController'
})
.state('box.child', {
url: '/child',
template: '<span>{{ definedProperty }}</span>'
});
})
});
Starting at the top, you name angular, call its module function, and give it the parameters ('theNameYouChose', ['dependencies','required'])
In the config bit there, you're telling it about dependencies config needs. $stateProvider and $urlRouterProvider are ui-router things, and $httpProvider is, I believe, an angular thing that is still necessary.
In the urlRouterProvider, you're providing the default address the website goes to: in this case it happens to be a template within a template, /signin from the signin state, and /child from the specifics pasted into signin
In the states, you are giving names and properties to the URLs that will be part of your app: like, if someone goes to index.html/signin, the 'signin' state is summoned.
The template within a template might be how you'd get the box variability that you're looking for. In box.html you will have another <div ui-view></div> and that's where the varying thing described in 'signin.child' gets put in.
box.html is also the place you put your specially created html tags, the ones you will make with the directive. I'll talk through those below.
The parent template, 'signin', talks about BoxController. Let's say you built that in box.js. It would look like this:
angular.module('yourApp.box', [])
.controller('BoxController', function ($scope) {
$scope.definedProperty = 'reRegPass',
$scope.arrayOfObjects = [{prop: 'red'},{prop: 'blue'}]
})
.directive('specificBox', function(){
return {
restrict: 'EA',
templateUrl: 'app/box/box-guts.html',
replace: true,
scope: {
source: '='
},
link: function(scope, element, attribute) {
element.on('click', function() {
alert('Functionality in specificBox is working');
}
}
}
});
The first line is again summoning angular module, and then naming it: note we already listed this, 'yourApp.box', as a requirement in app.js. Then we have the controller-naming function, and the appearance of specific properties in their $scope.
The directive is taking the more useful of the two forms a directive can take. They can either return functions (with signatures like the one in .link), or they can return objects that describe new HTML entities. This one is named specificBox, which Angular will translate into <specific-box></specific-box>. This object (technically called a 'directive definition object') can be translated into HTML tags because of the restrict property... 'E' is for element. 'A' is for attribute. I don't know how something that can be an element could also be an attribute, but having both options works, so I'm going with it. (Maybe for your various signin boxes you want a directive that has just 'A' to make new types of attributes.)
You put these specifically-crafted tags into box.html, and everything in box-guts.html will be between those tags... In fact, replacing those tags because of the replace: true.
The .link property is where you would put a function that would do something interesting to that element; turn it red if clicked, whatever. I have an alert example. Uses jQuery Lite for events.
The .scope property is odd. I believe if left off, the specific-box stuff would have the same controller as box (ie, BoxController), with box's scope and dependencies. But here, instead, we're making an isolate scope. box-guts will not depend on anything or have access to anything built before. How will it get interesting changeable data, then..? Every property in the scope object becomes an attribute on specific-box.
The '=' means that you will pass it objects from somewhere, and they will have 2-way data binding (changes made in box-guts will be reflected in the object collection in your app). Other options are '#', one-way data binding, which means you're passing box-guts a string or something that, if it changes in the DOM, you don't care to reflect in your app; or '&' to give it a function from a controller somewhere else in your app.
So ultimately, in box.html, you will have something like
<div class="box-holder">
<div ui-view></div>
<specific-box source="thing" ng-repeat="thing in arrayOfObjects"></specific-box>
</div>
Like I said above, ask questions and maybe we can sort this out.

how to process html using angular and bindings (?)

here is my testing page :
<div ng-controller="test">
<input ng-keyup="asIwrite($event)" />
<p id="entityContent"></p>
</div>
and my controller :
EntitiesApp.controller('test', ['$scope', function ($scope) {
$scope.asIwrite = function ($event) {
$('#entityContent').html($event.srcElement.value);
}
}]);
this is actually working, if i write click in the input, the paragraph will hold the clickable url (processed html).
I am using jQuery to update the content of the paragraph as to show html element as they render in the page..
But using jQuery is a work-around in my opinion.
I want to achieve that using just Angular. How can I do ?
note : sure I can sweep jQuery off my project and use innerHTML of the
element but I want to know the way of doing that in Angular with
bindings. I used ng-bind on a paragraph element but that just
render the value of the textarea as is, no html process is performed.
See working example below.
You are right by doubting using jQuery is the right thing to do, and as you would expect it is not. The angular way to do that is register your input into the scope using ng-model, and the way to display it is using the ng-bind-html directive. (or simply ng-bind if it was simple text with no HTML)
However, Angular will not allow HTML binding by default as it could be a security issue. If you are sure about what you write, you can use $scope.trustAsHtml as showed in my example.
angular.module('test', [])
.controller('test', ['$scope', '$sce', function ($scope, $sce) {
$scope.trust = function(content) {
return $sce.trustAsHtml(content);
}
}]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-controller="test">
<input ng-model="content"/>
<p ng-bind-html="trust(content)"></p>
</div>
You probably have tried to do something like this but the content doesn't come out as html
<input ng-model="input" />
<p id="entityContent" ng-bind-html="input"></p>
You need to ensure strict context escaping as described here:
https://docs.angularjs.org/api/ng/service/$sce
Please keep in mind what you're saying you want to do is explicitly prevented by angular developers as a way to mitigate XSS attacks
You don't need to do that, angular is simplier than that.
<div ng-controller="test">
<input ng-model="variable1" />
<p id="entityContent">{{variable1}}</p>
</div>
Angular binds variables automatically. When the input's value change, the new value will be printed.

In Angular JS - how to use ng-include to make my code generic and reusable?

Using the AngularJS,
I want to use ng-include to make my code generic.
So here is my problem:
I want to have my 'ang-attribute.html' file used in the ng-include to be as generic as possible, and for that I want to get the attribute name outside of the html.
With something like this:
<div data-field-name="display_name">
<div ng-include="'ang-attribute.html'"></div>
</div>
In my html file I would like to use the data-field-name, and then use it again with a different value.
I tried to get it via DOM... and couldn't find a way to do that.
So in my ng-include html file I have the following line:
<div ng-controller="attributeCtrl">
<div class="my-profile-constant-text">{{displayAttribute}}:</div>
....
</div>
Maybe there is a way to pass a constructor to the controller and then I could pass my data-field-name into it?
Or any other solution?
Thanks!
I believe you want to be looking at directives, this has an attributes object easily accessible after the dom has rendered to re-use.
Html
<my-directive field-name="display_name"></my-directive>
Directive
angular
.module("myApp", [])
.directive("myDirective", function() {
return {
restrict: "E",
template: "<div>{{exposeAttribute}}</div>",
//templateUrl: "mytemplate.html",
link: function(scope, element, attr) {
scope.exposeAttribute = attr.fieldName;
}
};
});
http://jsfiddle.net/mhCaD/

Categories