I'm using a directive to set html, css and javascript code inside of and iframe. These iframes are inside a ng-repeat, so there is an iframe per result.
Then these results are filtered by title and sortby title or date.
So, I have two problems:
Firefox is not showing the iframe html code but the rest of the browsers are.
After selecting a sort option, the title and date are refresing correctly, but the iframe content is not.
Here is a link to Plunker: http://plnkr.co/edit/Kvsbir?p=info
And here is my code:
<body ng-controller="HomeController">
<div class="panel-heading text-center">
<h3>Projects</h3>
<form action="" class="form-inline">
<div class="form-group">
<input class="form-control" type="text" ng-model="query.name" placeholder="Search...">
</div>
<div class="form-group dropdown">
<select class="btn btn-default dropdown-toggle" type="text" ng-model="sortOrder" ng-options="item.value as item.text for item in sortOptions"></select>
</div>
</form>
</div>
<div class="panel-body">
<div ng-model="result" ng-repeat="project in projects | orderBy:sortOrder | filter:query.name" class="col-md-4 col-sm-6">
<div class="single-pen">
<div class="meta">
<h3>{{project.title}}</h3>
<h6> {{project.created_at | date}} </h6>
</div>
<div class="iframe-wrap">
<div theframe="project"></div>
</div>
</div>
</div>
</div>
</body>
The controller
var app = angular.module('plunker', []);
app.controller('HomeController', function ($rootScope,$filter, $scope) {
'use strict';
var vm = this;
// Filter & sort
$scope.sortOptions = [
{ value: "-created_at", text: "Ordenar by Date"},
{ value: "title", text: "Ordenar by Title"}
];
$scope.sortOrder = $scope.sortOptions[0].value;
$scope.result = [
{
title: 'Project 1',
code: [{
css: "body{background-color: pink;}",
html: "<h1>Hello</h1>",
js: ""
}],
created_at: "2016-02-06T22:52:24.900Z"
},
{
title: 'Project 2',
code: [{
css: "body{background-color: blue;}",
html: "<h1>Hello</h1>",
js: ""
}],
created_at: "2016-02-10T11:52:33.055Z"
},
{
title: 'Project 3',
code: [{
css: "body{background-color: yellow;}",
html: "<h1>Hello</h1>",
js: ""
}],
created_at: "2016-02-06T22:52:24.900Z"
},
{
title: 'Project 4',
code: [{
css: "body{background-color: orange;}",
html: "<h1>Hello</h1>",
js: ""
}],
created_at: "2016-02-08T11:52:33.055Z"
},
{
title: 'Project 5',
code: [{
css: "body{background-color: red;}",
html: "<h1>Hello</h1>",
js: ""
}],
created_at: "2016-02-01T13:46:33.917Z"
},
];
$scope.projects = $scope.result;
})
.directive('theframe', function($compile){
return {
restrict: 'A',
scope: {
theframe: '='
},
template: '<iframe id="frame" scrolling="no"></iframe>',
link: function($scope, element, attrs) {
var $head = $(element).find('#frame').contents().find('head');
var $body = $(element).find('#frame').contents().find('body');
$scope.$watch('projects', function(n,o){
$head[0].innerHTML = '<style>'+$scope.theframe.code[0].css+'</style>';
$body[0].innerHTML = $scope.theframe.code[0].html + '<script> (function(){ \n' + $scope.theframe.code[0].js + '\n})();</script>';
}, true);
}
}
})
Any hints of why is not working correctly?
EDIT
SOLVED Firefox issue!
Thanks for the $timeout idea.
This is what i've changed: http://plnkr.co/edit/Kvsbir?p=preview
.directive('theframe', function($compile, $timeout){
return {
restrict: 'A',
scope: {
theframe: '='
},
template: '<iframe id="frame" scrolling="no"></iframe>',
link: function($scope, element, attrs) {
var $head = $(element).find('#frame').contents().find('head');
var $body = $(element).find('#frame').contents().find('body');
var timeout = setInterval(function(){
$head[0].innerHTML = '<style>'+$scope.theframe.code[0].css+'</style>';
$body[0].innerHTML = $scope.theframe.code[0].html + '<script> (function(){ \n' + $scope.theframe.code[0].js + '\n})();</script>';
$scope.$apply();
}, 500);
}
}
})
Related
I can't access the parent รค$scope in my $mdBottomSheet. Iwant be able to create this bottom sheet and click one of the buttons inside of it displaying the parent $scope data. I made a codepen.
That's the code by the way:
<div ng-controller="BottomSheetExample" class="md-padding bottomSheetdemoBasicUsage" ng-cloak="" ng-app="MyApp">
<div class="bottom-sheet-demo inset" layout="row" layout-sm="column" layout-align="center">
<md-button flex="50" class="md-primary md-raised" ng-click="showGridBottomSheet()">Show as Grid</md-button>
</div>
<div ng-if="alert">
<br>
<b layout="row" layout-align="center center" class="md-padding">
{{alert}}
</b>
</div>
<script type="text/ng-template" id="bottom-sheet-grid-template.html"><md-bottom-sheet class="md-grid" layout="column" ng-cloak>
<div>
<md-list flex layout="row" layout-align="center center">
<md-list-item ng-repeat="item in items">
<div>
<md-button class="md-grid-item-content" ng-click="listItemClick($index)">
<md-icon md-svg-src="{{item.icon}}"></md-icon>
<div class="md-grid-text"> {{ item.name }} </div>
</md-button>
</div>
</md-list-item>
</md-list>
</div>
</md-bottom-sheet>
</script>
</div>
JavaScript:
angular.module('MyApp',['ngMaterial', 'ngMessages', 'material.svgAssetsCache'])
.config(function($mdIconProvider) {
$mdIconProvider
.icon('share-arrow', 'img/icons/share-arrow.svg', 24)
.icon('upload', 'img/icons/upload.svg', 24)
.icon('copy', 'img/icons/copy.svg', 24)
.icon('print', 'img/icons/print.svg', 24)
.icon('hangout', 'img/icons/hangout.svg', 24)
.icon('mail', 'img/icons/mail.svg', 24)
.icon('message', 'img/icons/message.svg', 24)
.icon('copy2', 'img/icons/copy2.svg', 24)
.icon('facebook', 'img/icons/facebook.svg', 24)
.icon('twitter', 'img/icons/twitter.svg', 24);
})
.controller('BottomSheetExample', function($scope, $timeout, $mdBottomSheet, $mdToast) {
$scope.alert = '';
$scope.items = [
{ name: 'Hangout', icon: 'hangout' },
{ name: 'Mail', icon: 'mail' },
{ name: 'Message', icon: 'message' },
{ name: 'Copy', icon: 'copy2' },
{ name: 'Facebook', icon: 'facebook' },
{ name: 'Twitter', icon: 'twitter' },
];
$scope.listItemClick = function($index) {
var clickedItem = $scope.items[$index];
$mdBottomSheet.hide(clickedItem);
};
$scope.showGridBottomSheet = function() {
$scope.alert = '';
$mdBottomSheet.show({
templateUrl: 'bottom-sheet-grid-template.html',
controller: function () {
return this;
},
preserveScope: true,
bindToController: true,
clickOutsideToClose: true
}).then(function(clickedItem) {
$mdToast.show(
$mdToast.simple()
.textContent(clickedItem['name'] + ' clicked!')
.position('top right')
.hideDelay(1500)
);
});
};
})
.run(function($http, $templateCache) {
var urls = [
'img/icons/share-arrow.svg',
'img/icons/upload.svg',
'img/icons/copy.svg',
'img/icons/print.svg',
'img/icons/hangout.svg',
'img/icons/mail.svg',
'img/icons/message.svg',
'img/icons/copy2.svg',
'img/icons/facebook.svg',
'img/icons/twitter.svg'
];
angular.forEach(urls, function(url) {
$http.get(url, {cache: $templateCache});
});
});
I can't see the buttons/icons inside the sheet.
Fiddle: https://jsfiddle.net/uvkr9zwe/
You need to parse your parent controller scope in the right way by instancing and referencing the parent controller scope.
Check this demo fiddle:
Your scope Action:
.controller('BottomSheetExample', function($scope, $timeout, $mdBottomSheet, $mdToast) {
$scope.alert = '';
$scope.items = [
{ name: 'Hangout', icon: 'hangout' },
{ name: 'Mail', icon: 'mail' },
{ name: 'Message', icon: 'message' },
{ name: 'Copy', icon: 'copy2' },
{ name: 'Facebook', icon: 'facebook' },
{ name: 'Twitter', icon: 'twitter' },
];
$scope.showGridBottomSheet = function() {
$mdBottomSheet.show({
templateUrl: 'bottom-sheet-grid-template',
controller: function () {
this.parent = $scope;
},
controllerAs: 'ctrl',
clickOutsideToClose: true
}).then(function(clickedItem) {
$mdToast.show(
$mdToast.simple()
.textContent(clickedItem['name'] + ' clicked!')
.position('top right')
.hideDelay(1500)
);
});
};
})
View Template:
<script type="text/ng-template" id="bottom-sheet-grid-template">
<md-bottom-sheet class="md-grid" layout="column" ng-cloak>
<div>
<md-list flex layout="row" layout-align="center center">
<md-list-item ng-repeat="item in ctrl.parent.items">
<div>
<md-button class="md-grid-item-content" ng-click="listItemClick($index)">
<md-icon md-svg-src="{{item.icon}}"></md-icon>
<div class="md-grid-text"> {{ item.name }} </div>
</md-button>
</div>
</md-list-item>
</md-list>
</div>
</md-bottom-sheet>
</script>
I want to create <select ng-model='selected' ng-options='stage as stage.name for stage in stages'></select> element in variable as a string. As you see here, there are ng-... attributes inside the select element. If I use select element without ng-... attribute it is displaying without problem. If I use ng-... inside it, it's not showing anything. So, how do I make it display with ng-...? Please help.
My html code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="Scripts/angular.min.js"></script>
<script src="Scripts/angular-sanitize.js"></script>
<script src="Scripts/myScripts/index.js"></script>
</head>
<body>
<div ng-app="myapp" ng-controller="myCtrl">
<div ng-bind-html="htmlCode">
</div>
</div>
</body>
</html>
My js code:
var app = angular.module('myapp', ['ngSanitize']);
app.controller('myCtrl', ["$scope", function ($scope) {
$scope.stages =
[{ name: "Identification of Discontinuing Factors", value: 1 },
{ name: "Project Level Assessment", value: 2 },
{ name: "Organizational Readiness Assessment", value: 3 }];
$scope.htmlCode = "<select ng-model='selectedStage' ng-options='stage as stage.name for stage in stages'></select>";
}]);
you need to recompile the dom in order to work the ng- attributes. use this directive as an attribute to the ng-bind-html element.
.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, ele, attrs) {
scope.$watch(attrs.dynamic, function(html) {
ele.html(html);
$compile(ele.contents())(scope);
});
}
};
});
Demo
var app = angular.module('myapp', []);
app.controller('myCtrl', ["$scope","$sce", function ($scope,$sce) {
$scope.stages =
[{ name: "Identification of Discontinuing Factors", value: 1 },
{ name: "Project Level Assessment", value: 2 },
{ name: "Organizational Readiness Assessment", value: 3 }];
$scope.htmlCode = "<select ng-model='selectedStage' ng-options='stage as stage.name for stage in stages'></select>";
$scope.trust = function(html){
return $sce.trustAsHtml(html)
}
}]);
app.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, ele, attrs) {
scope.$watch(attrs.dynamic, function(html) {
ele.html(html);
$compile(ele.contents())(scope);
});
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myapp" ng-controller="myCtrl">
<div ng-bind-html="trust(htmlCode)" dynamic>
</div>
{{selectedStage}}
</div>
I am using angularjs and ng-include in in the view. I need to create a graphic using dygraph. I have 5 templates that show or hide when I click one button. When I click the button ng-include load a template. In this template, I have a div with Id where I want to show the graphic.
The problem is that this id doesn't exist in DOM when I click. If I click again, it shows the graphic without any problem because the Id exist.
My code:
View:
<button class="btn" ng-click="exploreLineChart()">Line chart</button>
<div ng-include="currentTemplate.url"></div>
Template:
<div id="linechart"></div>
Controller:
$scope.templates = [
{url: 'views/explore-dataset/summary.html', title: 'Summary'},
{url: 'views/explore-dataset/line-chart.html', title: 'Line Chart'},
{url: 'views/explore-dataset/bar-chart.html', title: 'Bar Chart'},
{url: 'views/explore-dataset/scatter.html', title: 'Scatter Plot'},
{url: 'views/explore-dataset/pie-chart.html', title: 'Pie Chart'},
{url: 'views/explore-dataset/correlation.html', title: 'Correlation'}
];
$scope.exploreLineChart = function ()
{
$scope.currentTemplate = $scope.templates[1];
linechart = new Dygraph(document.getElementById("linechart"),
$scope.csvContent,
{
height: 320
});
}
I advice you to create a directive to manage better the scope and graph state, for example:
Directive:
angular.module('tAngularApp').directive('ngGraphic', function() {
return {
restrict: 'A',
template: '<button class="btn" ng-click="exploreLineChart(0)">Summary</button><button class="btn" ng-click="exploreLineChart(1)">Line chart</button><div id="linechart"> </div>',
link: function($scope,element, attrs, ctrl) {
$scope.templates = [
{url: 'views/explore-dataset/summary.html', title: 'Summary'},
{url: 'views/explore-dataset/line-chart.html', title: 'Line Chart'},
{url: 'views/explore-dataset/bar-chart.html', title: 'Bar Chart'},
{url: 'views/explore-dataset/scatter.html', title: 'Scatter Plot'},
{url: 'views/explore-dataset/pie-chart.html', title: 'Pie Chart'},
{url: 'views/explore-dataset/correlation.html', title: 'Correlation'}
];
$scope.exploreLineChart = function (index) {
$('#linechart').text('displaying : ' + $scope.templates[index].title + ' template');
// TODO: Create the Graph
}
}
};
});
Html:
<div ng-graphic=""></div>
I have to implement nested Check all and Uncheck all in my web application using angular Js. I am struggling to implement those things and its models(checkall,unCheckall,sub Checks)should be updated inside the json. How to achieve it. Thanks In advance.
angular.module("app", []).controller("ctrl", function($scope) {
$scope.options = [{
value: 'Check All 1',
selected: false,
subList: [{
subSelect: false,
id: 1,
value: "check_1"
}, {
subSelect: false,
id: 2,
value: "check_2"
}]
}, {
value: 'Check All 2',
selected: false,
subList: [{
subSelect: false,
id: 3,
value: "check_1"
}, {
subSelect: false,
id: 4,
value: "check_2"
}]
}];
});
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body>
<div ng-app="app" ng-controller="ctrl">
<form id="selectionForm">
<div ng-repeat="option in options" ng-model="options">
<input type="checkbox" ng-click="toggleAll()" ng-model="option.selected">Check all
<br>
<div ng-repeat="sub in option.subList" ng-model="option.subList" style="margin:0px 15px">
<input type="checkbox" ng-model="sub.subSelect" ng-change="optionToggled()">{{sub.value}}
<div>
</div>
</form>
</div>
{{options}}
</body>
</html>
Implement toggleAll() something like this :
$scope.toggleAll = function(option) {
angular.forEach(option.subList, function(value, key) {
value.subSelect = option.selected;
});
};
And implement optionToggled() like this :
$scope.optionToggled = function(option) {
var flag = true;
angular.forEach(option.subList, function(value, key) {
flag = flag && value.subSelect;
});
option.selected = flag;
};
And notice that :
toggleAll() is now called on ngChange.
current option is passed to toggleAll() and optionToggled() as input param.
angular.module("app", []).controller("ctrl", function($scope) {
$scope.options = [{
value: 'Check All 1',
selected: false,
subList: [{
subSelect: false,
id: 1,
value: "check_1"
}, {
subSelect: false,
id: 2,
value: "check_2"
}]
}, {
value: 'Check All 2',
selected: false,
subList: [{
subSelect: false,
id: 3,
value: "check_1"
}, {
subSelect: false,
id: 4,
value: "check_2"
}]
}];
$scope.toggleAll = function(option) {
angular.forEach(option.subList, function(value, key) {
value.subSelect = option.selected;
});
};
$scope.optionToggled = function(option) {
var flag = true;
angular.forEach(option.subList, function(value, key) {
flag = flag && value.subSelect;
});
option.selected = flag;
};
});
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js">
</script>
<body>
<div ng-app="app" ng-controller="ctrl">
<form id="selectionForm">
<div ng-repeat="option in options"
ng-model="options">
<input type="checkbox"
ng-change="toggleAll(option)"
ng-model="option.selected">Check all
<br>
<div ng-repeat="sub in option.subList"
ng-model="option.subList"
style="margin:0px 15px">
<input type="checkbox"
ng-model="sub.subSelect"
ng-change="optionToggled(option)">{{sub.value}}
</div>
</div>
</form>
{{options}}
</div>
</body>
</html>
working link attached.
And here the code goes
$scope.toggleAll = function(index, torf){
$scope.options[index].subList.forEach(function(val){
val.subSelect = torf;
});
};
$scope.optionToggled = function(id){
$scope.options.forEach(function(val) {
if(val.id == id){var isTrue = true;
var isFalse = false;
val.subList.forEach(function(val1) {
if(!val1.subSelect||!isTrue)
isTrue = false;
if(val1.subSelect||isFalse)
isFalse = true;
});
if(isTrue){
val.selected = true;
}else{
val.selected = false;
}
}
});
};
Try this:
<div class="pull-left">
<a ng-click='checkAll()'>All</a> |
<a ng-click='uncheckAll()'>None</a>
</div>
<input type="checkbox" ng-model="data.selectedRecord" />
$scope.checkAll = function () {
$scope.checkList = [];
angular.forEach($scope.checkList, function (data){
data.selectedRecord = true;
$scope.checkList.push(data.id);
});
}
$scope.uncheckAll = function () {
angular.forEach($scope.checkList, function (data) {
$scope.checkList = [];
data.selectedRecord = false;
});
}
I am also using this.It is working for me.
I have added dynamically a textbox to the bottom of the ul as an option. When I try to type inside the focus is lost. If I remove the e.stopPropagation() and the use clicks on the textbox, then the list closes.
How can I type inside my custom textbox txtCategory the same way it allows typing on the 'Search' box without closing the list? The txtCategory has value '2' when loaded.
Here is the fiddle
Script
<script type="text/javascript">
var customOption = "<li class='multiselect4-item multiselect-filter' value='0'><div class='input-group'><input class='xxx' id='txtCategory' value='2'><input type='button' id='btnAddOption' value='Add'></div></li>";
$(document).ready(function () {
//$("#theChildx").hide();
$('#example-post-checkboxName').multiselect({
enableFiltering: true,
enableClickableOptGroups: true,
enableCollapsibleOptGroups: true,
includeSelectAllOption: true,
onDropdownShow: function (select, container) {
//var siz = parseInt($('#theParentx').height(),5) + parseInt($('#theParentx .multiselect-container').height(), 10) + parseInt($('#theChildx').height(),7);
//var w = $('#theParentx .multiselect-container').width();
//$('#theChildx').css({ 'top': siz + "px", 'width': w }).show();
},
onDropdownHide: function (event) {
//$("#theChildx").hide();
},
templates: {
divider: '<li class="multiselect-item divider"></li>',
liGroup: '<li class="multiselect-item group"><label class="multiselect-group"></label></li>'
}
});
var data = [{
title: 'First group',
children: [{ label: 'Cheese', value: 'cheese' , selected: true},
{ label: 'Tomatoes', value: 'tomatoes', selected: false, "attributes": {"some-attribute": 1, "another-attribute": false } }]
}, {
title: 'Second group',
children: [{ label: 'Mozzarella', value: 'mozzarella' },
{ label: 'Mushrooms', value: 'mushrooms' }]
}];
$("#example-post-checkboxName").multiselect('dataprovider', data);
$('.dropdown-menu').append(customOption);
//add actions on dynamically created button
$('.dropdown-menu').on("click", "#txtCategory", function (e) {
e.stopPropagation();
});
$('.dropdown-menu').on("click", "#btnAddOption", function () {
// alert('clicked');
var theValue = '<option>' + $('#txtCategory').val() + '</option>';
//$('#txtCategory').val();
$('#example-post-checkboxName').append(theValue);
$('#example-post-checkboxName').multiselect('rebuild')
{
$('.dropdown-menu').append(customOption);
alert('ok');
};
return false;
});
});
</script>
HTML
<div class="form-group">
<label class="col-sm-2 control-label">Multiselect</label>
<div class="col-sm-10">
<div id="theParentx">
<select id="example-post-checkboxName" name="multiselect[]" aria-labelledby="dropdownMenu3" multiple="multiple" required>
</select>
<div id="theChildx" class="dropdown-menu">
<input />
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default input-group-addon">Submit</button>
</div>
</div>
Add keydown event along with click to your dynamic textbox as below:
$('.dropdown-menu').on("keydown click", "#txtCategory", function (e) {
e.stopPropagation();
});
Updated Fiddle Here