I have some divs positioned as follows:
<div style="top: {{ item.top }}px;"></div>
In my controller, I have an array of elements:
$scope.things = [{ "top": 10}];
I have JavaScript function in my controller that gets fired somewhat rapidly:
MyFunction.thingThatRunsCallbackRapidly(function(newTopValue) {
$scope.things[0].top = newTopValue;
});
The top value of the things updates properly, but the element won't actually change its position until some other binding in my controller changes. What gives?
Try to use ng-style instead of style if you want to dynamically update the value.
ng-style="{'top': item.top + 'px'}"
https://docs.angularjs.org/api/ng/directive/ngStyle
Related
I want to dynamically create a button for each paragraph that is created inside a contenteditable div. I've been thinking a lot and can't come up with a good solution. The things I've thought about are
putting the button and paragraph together into one directive and have the content editable add a new <button+p> tag each time the user hits return. This has the benefit of having both the button and the paragraph use the same controller, but it leaves the button in the content editable div so it can be deleted...
Use the Model to maintain an array of all paragraphs in the div, then create buttons for each of the paragraphs in this array. My question here is: if I update the model with new paragraphs, will the buttons automatically be generated? If I use ng-repeat?
I'm kind of at a loss of the best way to approach this. Should I try to build the button and the paragraph together? Or is there a better way of separating them but binding them together so that when the button is clicked I can change the styling of the paragraph?
Create a directive and associate it to your div.
Ex:
Define as binding a parameter with two way data binding, the ones that will keep track of the p elements created inside the div and that will be passed from the the controller associated to your view.
Inject inside your link function of the directive the $element.
Then bind to the div with contenteditable the input event in order to detect edits in the div.
Inside this code get the total number of p children of your div, and associate it to the variable allowed from the directive.
In this way your parameter is always sync with the number of p inside your div, and it can be accessed from outside scopes because you pass it from outside.
Then inside your view, use a ng-repeat iterating over this parameter you passed in the directive, and create your dynamic content inside the ng-repeat.
HTML Code:
<div ng-app="myApp">
<div ng-controller="Controller">
<div contenteditable="true" p-inspector p-elements="pElementsNumber">
TEST
</div>
{{pElementsNumber}}
<div ng-repeat="p in returnArrayFromNumber() track by $index">
P detected
</div>
</div>
</div>
Here the JS code:
angular.module('myApp', [])
.controller('Controller', ['$scope', function($scope) {
$scope.pElementsNumber = 0;
$scope.returnArrayFromNumber = function () {
return new Array($scope.pElementsNumber);
};
}])
.directive('pInspector', function($rootScope) {
return {
restrict: 'A',
scope: {
pElements: '='
},
link: function ($scope, $element, $attrs) {
$element.on("input", function(e) {
var htmlString = $element.text();
var regex = /<p>[^<p><\/p>]*<\/p>/gi, result, count = 0;
var count = 0;
while ( (result = regex.exec(htmlString)) ) {
count++;
}
$scope.pElements = count;
$rootScope.$apply();
});
}
};
});
Here the running example: https://jsfiddle.net/a0jwmpy4/81/
Just one recommendation: if you want to detect more elements, make this directive dynamic accepting the name of the elements in the parameters and detecting all of them. Please do not create a single directive for every element you want to detect inside the div :)
Hope this helps
Have you tried to use ng-repeat for each paragraph/modal then set all your code in each repeat something like below
<div>
<p ng-repeat="paragraph in paragraphs"> {{contentsOfParagraph}} <button ng-click="editParagraph(MayBeIDOfParagraph)">Edit</button></p>
</div>
now your js code will have a function editParagraph that pass the ParagraphID
How to access variable from controller to javascript?
Controller:
$scope.coveragedetailjson = $rootScope.getEligibilityData;
In this variable I get the JSON data. And I want to access the value in JavaScript and assign that value to the div.
Html:
<script>
var detail = $('[ng-controller="getcoveragedetailController"]').scope().coveragedetailjson;
alert(detail);
<script>
Then I want to assign this detail value to div. How can I do that?
You can attach your controller to the view with the ng-controller directive.
For example:
<div ng-controller="Ctrl">
{{ coveragedetailjson }}
</div>
this code bind the $scope.coveragedetailjson inside the div.
What do you mean by 'assign this detail value to div'?
This should insert detail to div -
DivElement.innerHtml = DivElement.innerHtml + JSON.stringify(detail);
But what you are doing is very bad design. Consider using data binding {{detail}} and if you need to pass it from one directive to another to it width Service
In this you can directly access json data by key value and store it to div element For ex.
<script>
var detail = $('[ng-controller="getcoveragedetailController"]')
.scope().coveragedetailjson;
$(divelement).html(JSON.stringify(detail));
</script>
Or You can do this by this way
<div ng-controller="Ctrl">
<div ng-repeat="x in coveragedetailjson">
{{ x.keyname }}
</div>
</div>
You can use second way for print item in div element
I am trying to set an observable with a specific background color that will be called in the views. I created my observable but now when i apply it to the style binding - nothing happens when i render the page.
Here is what i have:
self.color = ko.observable(data.color || '');
i have set in my data: color:'background-color: #E91E63'
my view:
<div class="info" data-bind="style: color"></div>
when i run the page the div is still white and didn't change colors - not sure where i could be going wrong.
self.bg_color = ko.observable(data.color || 'red');
then in html.
<div class="info" data-bind="style:{ 'background-color' : $data.bg_color() }"></div>
Style binding is similar to style tag in html. you have to provide attribute whose value needs to be updated.
eg: style:{background:color}
Also you can check this JSFiddle reference
So I have an ng-repeat that loops over data objects and displays it in a list directive. One of the objects in the list should use the abbreviated version when the length of the text element is equal to or exceeds the length of the container. So what I have is this:
//this is the list directive
<shift-list selection="selection" shifts="shifts"></shift-list>
//this is the template of the list directive that adds site-base-name directive
<ion-item collection-repeat="shift in shifts">
<div class="item-text">
<site-base-name shift="shift"></site-base-name>
</div>
//and here is what my site-base-name directive looks like
return {
restrict: 'E',
link: function(scope, element) {
$timeout(function(){
scope.siteBaseWidth = element[0].offsetWidth;
scope.parentWidth = element.parent()[0].offsetWidth;
});
},
replace: true,
scope: {
shift: '='
},
template: ''+
'<div class="sitebase">{{(siteBaseWidth + 20 >= parentWidth) && shift.sites_abbreviation || shift.sites_name }} : {{shift.bases_name}}</div>'
}
}
So what I'm doing is nesting the directive site-base-name inside the list directive and then finding the size of the element and its parent. Then I'm using the abbreviated version of the name (shift.sites_abbreviation) if the size exceeds my condition (siteBaseWidth + 20 >= parentWidth). The problem with this is the behavior I'm getting is buggy and inconsistent. It also applies the changes after the DOM is loaded, so you can see the text change within the window.
My question is what is the best way to find the width of the text element and parent element then apply a condition that decides what data to populate the binding with? Preferably a clean Angular solution.
Relying on the element offsetWidth is not very clean, as if forces you to wait for the DOM to be updated (hence your $timeout and the flickering observed).
A cheap way to solve your issue would be to initially display your text with an opacity of 0.01 (so it is not visible, but still takes some space), and with your site-base-name directive, once you know its size and adjust the text, you can set its opacity back to 1.
Now a better solution would be to get rid of this $timeout and offsetWidth. If you use a monospace font, you could just calculate thestring.length times pixelsPerCharacter, before even it is displayed.
I have the html Structure that I need to update from the json data. My Json data is in a Controller. I need to write an expression for ng-click event that will read the json data and put the in the corresponding div in html. but I am not sure how to acheive this.
Below is what I have so far.
<body data-ng-app>
<div class="container" data-ng-controller="UpdateDataCtrl">
<div class="inner1"></div>
<div class="inner2"></div>
</div>
UPdate Controllers
</body>
function UpdateDataCtrl($scope) {
$scope.data = [
{
"USA":"Eglish",
"Pop":"232423432432"
},
{
"France":"French",
"Pop":"1212323432"
},
{
"Spain":"Spainish",
"Pop":"3432432"
}
]
}
On each click the 2 Div should get updated from the json. First div should have USA---English Pop---2342234232 and then on next click the div should have data from France and so on.
http://jsfiddle.net/MBFpD/1/
Thanks
It appears that you are unclear on the concept of AngularjS. You don't want to update the DIVs. You want to reference your model and then change the data in your model.
For example you can write the div like this:
<div class="inner1">Population: {{data[dataindex].Pop}}</div>
Then in the Controller you initialize the dataindex to 0, so that this will output the population from the first entry in the array:
$scope.dataindex = 0;
The click function (you must have the link with the ng:click inside the block governed by the Controller!) could then just increase the dataindex by one and by using modulo restart at 0 again when the end of the array was reached.
$scope.click = function() {
$scope.dataindex = ($scope.dataindex+1) % $scope.data.length;
Here is an updated and modified jsfiddle of your example which will show everything in action: http://jsfiddle.net/MBFpD/2/
Bind your data to your scope when you click on the link:
$scope.update = function() {
$scope.data = data; //your array defined locally to the scope
};
ng-repeat your data bound to the scope; display the container if the size of the array is > 0.
Use {{index}} to get the iteration variable inside the loop.
Above all, move your ng-controller declarative at the top to enclose both your ng-repeat and your ng-click; otherwise, AngularJS cannot guess what you want to achieve.
http://jsfiddle.net/MBFpD/5/