Using contenteditable div for two way binding - angularjs

I want to display the contents from my model in a div which is contenteditable. User will modify this content and it should get saved in my model. I have used the example provided at https://docs.angularjs.org/api/ng/type/ngModel.NgModelController.
The code is available at http://plnkr.co/edit/ruKtNfDWP17npbFU4Te9?p=info
var app = angular.module('docApp', []);
The issue is:
ng-model attribute does not output the data in the div as it does in the input control. Therefore I have to use binding expression.
Because of that editing goes beserk.
How do I get it right?
Thanks.

In my experience contenteditable is extremely tricky for angular to deal with. See this issue on github (which has been open for over 3 years) for a lengthy discussion. You may want to try some third party modules such as akatov/angular-contenteditable.

Related

How to find and replace a specific text on a page

How to find and replace a specific text on a html page using AngularJs
That text is on a third party component so the id and the class is keeping changing. What I can reference is the text itself that I want to change.
That specific text on the html page is no class or id or any ng-tag around it.
I am not a angularjs developer and the page was built on asp.net mvc with the view (cshtml) using angularjs version1.
Is there a way in angularjs to find and place the text like the way in javascript:
document.body.innerHTML = document.body.innerHTML.replace('old_text', 'new_text');
Thank you!
In angularjs each application state(page) has a controller. The logic to access the Dom should placed in said controller.
To manipulate the DOM please see this answer
In Angular world, it's called data binding. Here are the official docs on data binding.
Here is the working DEMO of data being updated in time. First, html displays "Initial Text" and in 5 seconds it's changed to "New Text".
What was done for this demo:
An angular component was created with a dedicated variable $scope.text that holds text values that will change in time.
Then, this variable is used in the HTML markup, like this: {{ text }}.
Angular handles the HTML re-rendering automatically for you, so when the value of $scope.text is modified in the component, Angular forces re-rendering of the html in the browser
UPD another example with Angular two-way binding: DEMO.
Here user can change $scope.text value in the input field, which automatically changes its value in the controller. Try to edit the input field and you will see how it instantly updates in the header above the input field.

ChartistJS : Converting jQuery solution to AngularJS

I am using Chartist JS for my charts in my Angular JS app. The issue is I am seeing this here. There is a JS bin that highlights the issue. The author gives a solution for it. The solution is doing DOM manipulations in Jquery which is easy to do. However with AngularJS the way you manipulate the DOM is via Directives. I have created a plunker here which highlights the same issue in Angular JS but I am confused as to how to put the solution provided by author into my Angular code.
Here is the solution
$('[data-tab]').on('toggled', function (event, tab) {
tab.find('.ct-chart').each(function(i, e) {
e.__chartist__.update();
});
});
Edit: As requested the JSFiddle is updated, so what I am trying to do is. I have three different tabs and three different graphs, whenever I click on them I should see the respective graph. To make the tab behavior possible I have written a basic code using scope and model. which facilitates the changing of tabs. The issue is that the chart is getting created for first or default tab but not for the second and third tab. There is a solution given by the author but I don't know how to implement that in AngualrJS
the jQuery solution that you post is basically finding all the chart references and then doing DOM manipulation and call the update() function.
The key is how to find the chart to update in Angular.
In this case, you can assign a variable when you create a chart. For example:
var chart4 = new Chartist.Bar('#chart4', data1);
var chart5 = new Chartist.Bar('#chart5', data2);
Now you have the reference of the chart. All you have to do is to call update() function to render the chart again.
if (value === "allDrivers") {
$scope.tab = "All";
chart4.update();
}
Here is the working plunker
One thing I like to point out is: right now you need to double click the tab in order to see the chart is being rendered or you resize the browser window. I am still trying to find a way to fix this. But at least this approach gives you an idea how to convert the jQuery solution to Angular solution.
I was able to solve this using angular.element() method. So if you wish you use jquery in your angular code. You have to do this via angular.element method. But make sure to include jquery before angular in your index.html
If jQuery is available, angular.element is an alias for the jQuery
function. If jQuery is not available, angular.element delegates to
Angular's built-in subset of jQuery, called "jQuery lite" or jqLite.
I did not know this. From here it was learning for me. Following advice of #pieterjandesmedt from this post. I was able to do this. For other people who want to learn how this works. I have created a GitHub repo which gives a solution to this issue. The link for problem is given in the question. Hope that helps

Using Angular-Bacons $scope.$watchAsProperty(property) in Angulars ng-repeat

I´m trying to find a good way to use Baconjs together with Angularjs in conjuctions with Angular-Bacon.
Now digesting from Bacon to the Angular scope works perfectly fine but I´m stumbling with Angular-Bacons $scope.$watchAsProperty(property) within Angulars ng-repeat:
Let´s say I have the Angular scope $scope.databaserecords and render it out with:
<div ng-repeat="record in databaserecords">
Each of the records has a record.checked property and I want to handle all checked records together in one Bacon stream, for example to add a certain tag to all records at once.
At this point using $scope.$watchAsProperty(databaserecords) I get no Bacon events when checking or unchecking certain records, so how could I accomplish to receive these changes back in Bacon?
I might also mention, that using $scope.$watchAsProperty(property) out of ng-repeat, for example for input fields, works well without any problem.
Thanks for your help! :)
If I've understood correctly, your actual databaserecords remains the same throughout the scope, so you'll need to invoke $watchAsProperty with the objectEquality argument set to true:
$scope.$watchAsProperty("databaserecords", true)
By default angular opts to compare objects with a simple object equality check. In your case the list object remains the same, so a deeper check is necessary. This is already implemented in angular-bacon but it seems I've omitted it from the docs.

AngularJS jquery.flot chart directive DOM collision

i'm working with angular js now for about ke 4 months and despite all the "first step failures" like not emphasising the async way anuglar thinks, I'm facing a problem I don't really understand. It's not that easy to describe.
I have a provider which registrates directives within the routeprovider's resolve function - during config phase. To compile programmatically preconfigured directives I create them on the specific controller call of each route. Acutally the directive I'm adressing here is a complex flotchart directive. It retrieves data from a rest api, transformes the retrieved data and prepares different kinds of option setups like proper stacked line charts or simple piecharts. Every single step takes its time, so I introduced promises to be sure that everthing is at it's right place before I finally call something like "$.plot".
So now I have the following situation: Imagine a singlepage app with two tabs. Each tab - like a first class menu item - refers to a new page with a new controller to process and new partials to render. For each page i have beside other directives one of these heavy flotchart directives to render. actually it takes about 5 seconds to render the chart. So we assume that we really start the app from beginning - like pressing F5. Now I enter the first page the first time and within the mentioned 5 seconds I switch tabs to enter the next page. I get to the next page, see different partials, layouts and stuff and a loading chart - but actually the directive of the first page is still bound to its link phase of that heavy flotchart directive (still preparing options for flot and calculating data to output graphically).
My problem is that this link phase actually really ends within a completely different template/route/controller context and gets stuck. It crashes with a console "replace" error from jquery.flot. I think this error means that flot tries to plot into a div which does not exist anymore. But that error occures just when I switch tabs during the link phase of the first page's heavy flot directive. It doesn't happen when the first page's chart is fully rendered and doesn't happen when the first page's directive hasn't entered its link phase (or am i missing something??). I tried placing some console.logs directly BEFORE hitting the jquery "$.plot" - remember only of the first page chart directive to dive into what's acutally happening. And the strange thing is when I manage to switch tabs within these magic 5 seconds, I still get the console log entries from the first page entry although I'm on a different page. And now guess what. That's strange - acutally two directive link phases are running side by side and one of them on a completely different view (or isn't it completely different, because its a singel page app?). Imagine I plot ("render") the chart in exactly the same div id - like $('#flot-chart'). so I have html parts containing id="flot-chart" on the first page AND on the second. when I now switch from the first to the second page (not finishing the first chart) I get the chart from the first page rendered in the #flot-chart div of the second page and like half a second later the actually correct chart rendered in that same div. So actually the link phase of the first page's chart directive ends in a completely different page in a way showing 2 charts consecutively. I know jquery.flot depends on DOM manipulation via jquery and that might be the problem (perhaps THAT'S the only real explanation for my problem), because jquery DOM manipulation is out from the angular way of life.
Or are there other explanations? I acutally solved the problem via $routeChangeStart listening and killing the $.plot process, but are there some hints, suggestions, explanations for that behaviour?
Plunker flot chart directive DOM collision
I have prepared a plunker which shows kind of a similar behaviour. i've delayed the creation of the directive and the directive's async data and option retrieval methods to somehow mock the behaviour of my app. this is non production code but describes simplified the way my problems occure. when you "fast click" the menu item one after the other many times, you can sometimes force angular to show 2 charts in one page. acutally one directive is linking and doing stuff in a different partial ? i know i'm missing something in my mind ... please give me a hint.
i used chrome for reproducing the error. stop the the plunker and press 'run'. directly after pressing 'run' click as fast as you can both links a couple of times.
Thanks a lot!

Image crop with AngularJS

I want to let the user crop an image, I found this JQuery plugin - http://deepliquid.com/content/Jcrop.html
I tried to use it with Angular-ui's Jquery passthrough option, adding the ui-jq=Jcrop directive to the <img>
The problem is that If I use ng-src to dynamically change the image it doesn't work and nothing is seen. If I change it to src and put a static url I can see the image and Jcrop.
how can I fix that ?
also, how can I listen to Jcrop's callbacks to know what is the user's selection ?
is there a better / simpler way to add image cropping functionality to AngularJS ?
Here is my solution:
I've written a directive that create img element and apply plugin on it. When src is changed, this img is removed and content that was created by plugin is also destroyed and then re-created new img with new src and again applied plugin on it.
Also provided 'selected' callback to be able to get coordinated that were selected (wrapped in $apply so you can modify your scope values in it).
Check my solution at Plunker
I've built a demo using AngularJS and Jcrop here:
Demo: https://coolaj86.github.com/angular-image-crop
On Github: https://github.com/coolaj86/angular-image-crop
You can leverage ui-event to create an event definition object with the keys being the event names and the values being the callbacks. Or you can simply pass these events as options to Jcrop (according to the documentation)
Finally, there is a new update coming to ui-jq that lets you add ui-refresh which is an expression to be watched to re-trigger the plugin.
Theoretically you should be able to do
<img ui-jq="Jcrop"
ui-options="{onSelect:myCallback}"
ui-event="{onChange:'myCallback($event)'}"
ui-refresh="imgSrc"
ng-src="imgSrc" />
Note: this simply re-fires the passthrough again, and doesn't automatically mean this will fix the problem or that the plugin will behave properly when re-initialized
We're still working on a good way to allow you to trigger different events at different times.

Resources